Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 17 additions & 6 deletions src/app/(authenticated)/dashboard/loans/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,14 @@ export default function LoansPage() {
}

const headerActions = (
<div className="flex w-full flex-col gap-2 sm:w-auto sm:flex-row sm:items-center">
<div className="grid w-full grid-cols-1 gap-2 sm:w-auto sm:grid-cols-none sm:flex sm:items-center">
{activeTab === 'my-loans' && myLoans.length > 0 && (
<Button onClick={() => setShowSelection(!showSelection)} variant="outline" size="sm">
<Button
onClick={() => setShowSelection(!showSelection)}
variant="outline"
size="sm"
className="w-full sm:w-auto"
>
{showSelection ? 'Cancel' : 'Select'}
</Button>
)}
Expand All @@ -90,22 +95,28 @@ export default function LoansPage() {
onValueChange={v => switchTab(v as typeof activeTab)}
className="space-y-6"
>
<TabsList className="grid w-full grid-cols-3">
<TabsTrigger value="my-loans" className="gap-2">
<TabsList className="grid h-auto w-full grid-cols-3 gap-1 p-1">
<TabsTrigger
value="my-loans"
className="min-h-10 gap-1 px-2 text-xs sm:gap-2 sm:text-sm"
>
<DollarSign className="h-4 w-4" />
<span className="hidden sm:inline">My Loans</span>
<span className="sm:hidden">Mine</span>
{myLoans.length > 0 && <span className="ml-1 text-xs">({myLoans.length})</span>}
</TabsTrigger>
<TabsTrigger value="available" className="gap-2">
<TabsTrigger
value="available"
className="min-h-10 gap-1 px-2 text-xs sm:gap-2 sm:text-sm"
>
<Target className="h-4 w-4" />
<span className="hidden sm:inline">Available</span>
<span className="sm:hidden">Browse</span>
{availableLoans.length > 0 && (
<span className="ml-1 text-xs">({availableLoans.length})</span>
)}
</TabsTrigger>
<TabsTrigger value="offers" className="gap-2">
<TabsTrigger value="offers" className="min-h-10 gap-1 px-2 text-xs sm:gap-2 sm:text-sm">
<TrendingUp className="h-4 w-4" />
<span className="hidden sm:inline">My Offers</span>
<span className="sm:hidden">Offers</span>
Expand Down
4 changes: 2 additions & 2 deletions src/components/dashboard/MobileDashboardSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ export function MobileDashboardSidebar({ stats }: MobileDashboardSidebarProps) {
<TrendingUp className="w-5 h-5 text-fg-secondary" />
<h3 className="text-base font-semibold text-fg-primary">Your Impact</h3>
</button>
<div className="grid grid-cols-2 gap-3 mb-3">
<div className="mb-3 grid grid-cols-1 gap-3 sm:grid-cols-2">
<div className="rounded-md border border-subtle bg-surface-raised/30 p-3 text-center">
<div className="text-2xl font-bold text-fg-primary">{totalProjects}</div>
<div className="text-xs text-fg-secondary">Projects</div>
</div>
<div className="rounded-md border border-subtle bg-surface-raised/30 p-3 text-center">
<div className="text-lg font-bold text-fg-primary">
<div className="break-words text-lg font-bold text-fg-primary">
<CurrencyDisplay amount={totalRaised} currency={primaryCurrency} />
</div>
<div className="text-xs text-fg-secondary">Raised</div>
Expand Down
10 changes: 5 additions & 5 deletions src/components/dashboard/sections/DashboardHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ export function DashboardHeader({ profile, totalProjects, totalDrafts }: Dashboa

return (
<div className="oc-surface oc-surface-padding">
<div className="flex items-center justify-between gap-4">
<div className="flex items-center gap-4">
<div className="oc-accent-tile">
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
<div className="flex min-w-0 items-center gap-3 sm:gap-4">
<div className="oc-accent-tile flex-shrink-0">
<User className="h-5 w-5" />
</div>
<div className="min-w-0 flex-1">
Expand All @@ -82,14 +82,14 @@ export function DashboardHeader({ profile, totalProjects, totalDrafts }: Dashboa
</p>
</div>
</div>
<div className="flex items-center gap-2 shrink-0">
<div className="flex w-full flex-col gap-2 sm:w-auto sm:flex-row sm:items-center sm:shrink-0">
{totalProjects === 0 && (
// Cat-first: instead of hardcoding project creation as the
// canonical first step, route to Cat. Always visible on mobile
// — header used to have no action affordance on <sm because of
// a `hidden sm:flex` that wasted the founder's primary viewport.
<Link href={ROUTES.DASHBOARD.CAT}>
<div className="flex items-center gap-1.5 rounded-md bg-fg-primary px-3 py-1.5 text-sm font-medium text-fg-inverted transition-colors hover:bg-muted-strong">
<div className="flex min-h-10 w-full items-center justify-center gap-1.5 rounded-md bg-fg-primary px-3 py-1.5 text-sm font-medium text-fg-inverted transition-colors hover:bg-muted-strong sm:w-auto">
<Sparkles className="h-4 w-4" />
Ask Cat
</div>
Expand Down
18 changes: 9 additions & 9 deletions src/components/dashboard/sections/DashboardProjects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ export function DashboardProjects({ projects }: DashboardProjectsProps) {
return (
<Card>
<CardHeader>
<div className="flex items-center justify-between">
<div>
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<div className="min-w-0">
<CardTitle>Projects</CardTitle>
<CardDescription>Your projects</CardDescription>
</div>
<Link href={ENTITY_REGISTRY.project.createPath}>
<Button size="sm">
<Button size="sm" className="w-full sm:w-auto">
<BarChart3 className="w-4 h-4 mr-2" />
Create Project
</Button>
Expand All @@ -58,14 +58,14 @@ export function DashboardProjects({ projects }: DashboardProjectsProps) {
Not sure what to create? Ask Cat — it can suggest the right shape (project, wishlist,
cause, service…) based on what you want to do.
</p>
<div className="flex flex-col sm:flex-row gap-2 justify-center">
<div className="mx-auto grid max-w-sm grid-cols-1 gap-2 sm:grid-cols-2">
<Link href={ROUTES.DASHBOARD.CAT}>
<Button variant="outline" size="sm">
<Button variant="outline" size="sm" className="w-full">
Ask Cat
</Button>
</Link>
<Link href={ENTITY_REGISTRY.project.createPath}>
<Button variant="ghost" size="sm">
<Button variant="ghost" size="sm" className="w-full">
Create a project
</Button>
</Link>
Expand All @@ -79,15 +79,15 @@ export function DashboardProjects({ projects }: DashboardProjectsProps) {
return (
<Card>
<CardHeader>
<div className="flex items-center justify-between">
<div>
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<div className="min-w-0">
<CardTitle>Projects</CardTitle>
<CardDescription>
Your projects ({projects.length} {projects.length === 1 ? 'project' : 'projects'})
</CardDescription>
</div>
<Link href={ENTITY_REGISTRY.project.basePath}>
<Button variant="outline" size="sm">
<Button variant="outline" size="sm" className="w-full sm:w-auto">
<BarChart3 className="w-4 h-4 mr-2" />
View All
</Button>
Expand Down
8 changes: 4 additions & 4 deletions src/components/dashboard/sections/DashboardQuickActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,24 @@ export function DashboardQuickActions() {
<CardDescription>Common tasks</CardDescription>
</CardHeader>
<CardContent>
<div className="flex flex-wrap gap-3">
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2 xl:grid-cols-3">
<Link href={ROUTES.DASHBOARD.CAT}>
<Button
variant="outline"
className="min-h-11 hover:border-strong hover:bg-surface-raised"
className="min-h-11 w-full justify-start hover:border-strong hover:bg-surface-raised"
>
<Cat className="w-4 h-4 mr-2" />
Ask Cat
</Button>
</Link>
<Link href={ENTITY_REGISTRY.project.basePath}>
<Button variant="outline" className="min-h-11">
<Button variant="outline" className="min-h-11 w-full justify-start">
<Eye className="w-4 h-4 mr-2" />
Manage Projects
</Button>
</Link>
<Link href={ROUTES.PROFILE.SELF}>
<Button variant="outline" className="min-h-11">
<Button variant="outline" className="min-h-11 w-full justify-start">
<Star className="w-4 h-4 mr-2" />
Update Profile
</Button>
Expand Down
22 changes: 13 additions & 9 deletions src/components/entity/variants/LoanCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function LoanCard({ loan, viewMode = 'grid' }: LoanCardProps) {
return (
<Link href={`${ENTITY_REGISTRY['loan'].publicBasePath}/${loan.id}`}>
<Card className="oc-card-link">
<div className="flex items-center p-4 gap-4">
<div className="flex flex-col gap-4 p-4 sm:flex-row sm:items-center">
{/* Icon */}
<div className="oc-icon-tile h-12 w-12">
<DollarSign className="w-6 h-6 text-fg-primary" />
Expand All @@ -52,7 +52,7 @@ export function LoanCard({ loan, viewMode = 'grid' }: LoanCardProps) {
</div>

{/* Stats */}
<div className="flex items-center gap-4 text-sm">
<div className="flex flex-wrap items-center gap-2 text-sm sm:justify-end">
{loan.interest_rate && (
<Badge variant="secondary" className="gap-1">
<Percent className="h-3 w-3" />
Expand Down Expand Up @@ -83,32 +83,36 @@ export function LoanCard({ loan, viewMode = 'grid' }: LoanCardProps) {
}
progressSlot={
<div className="space-y-2">
<div className="flex items-center justify-between">
<div className="flex flex-col gap-1 sm:flex-row sm:items-center sm:justify-between">
<span className="text-sm text-fg-secondary">Remaining</span>
<span className="font-semibold text-fg-primary">
<span className="break-words font-semibold text-fg-primary sm:text-right">
{formatAmount(loan.remaining_balance, loan.currency)}
</span>
</div>
<Progress value={progress} className="h-1.5" />
<div className="flex justify-between text-xs text-fg-secondary">
<div className="flex flex-col gap-1 text-xs text-fg-secondary sm:flex-row sm:justify-between">
<span>{progress.toFixed(0)}% funded</span>
<span>{formatAmount(loan.original_amount, loan.currency)} total</span>
<span className="break-words sm:text-right">
{formatAmount(loan.original_amount, loan.currency)} total
</span>
</div>
</div>
}
metricsSlot={
loan.interest_rate || loan.monthly_payment ? (
<div className="flex items-center justify-between text-sm">
<div className="flex flex-col gap-2 text-sm sm:flex-row sm:items-center sm:justify-between">
{loan.interest_rate && (
<div className="flex items-center gap-1">
<Percent className="h-3 w-3 text-fg-tertiary" />
<span>{loan.interest_rate}% APR</span>
</div>
)}
{loan.monthly_payment && (
<div className="flex items-center gap-1">
<div className="flex min-w-0 items-center gap-1">
<TrendingUp className="h-3 w-3 text-fg-tertiary" />
<span>{formatAmount(loan.monthly_payment, loan.currency)}/mo</span>
<span className="min-w-0 break-words">
{formatAmount(loan.monthly_payment, loan.currency)}/mo
</span>
</div>
)}
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/components/loans/sections/CollateralSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export function CollateralSection({
))}
{/* Create Asset Option */}
<SelectItem value="__create_asset__" className="text-fg-primary font-medium">
Create New Asset
Create New Asset
</SelectItem>
</SelectContent>
</Select>
Expand All @@ -106,7 +106,7 @@ export function CollateralSection({
)}
</div>

<div className="grid grid-cols-2 gap-4">
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
<div>
<FormLabel>Pledged Value</FormLabel>
<Input
Expand Down
4 changes: 2 additions & 2 deletions src/components/loans/sections/FinancialDetailsSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export function FinancialDetailsSection({ control }: FinancialDetailsSectionProp
<CardDescription>Current loan information</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="grid grid-cols-2 gap-4">
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
<FormField
control={control}
name="original_amount"
Expand Down Expand Up @@ -82,7 +82,7 @@ export function FinancialDetailsSection({ control }: FinancialDetailsSectionProp
/>
</div>

<div className="grid grid-cols-2 gap-4">
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
<FormField
control={control}
name="interest_rate"
Expand Down
8 changes: 4 additions & 4 deletions src/components/loans/sections/PreferencesSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ export function PreferencesSection({ control }: PreferencesSectionProps) {
<CardDescription>Control how your loan appears to potential offerers</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="flex items-center justify-between">
<div className="space-y-0.5">
<div className="flex flex-col gap-3 rounded-md border border-subtle p-3 sm:flex-row sm:items-center sm:justify-between">
<div className="min-w-0 space-y-0.5">
<FormLabel>Public Listing</FormLabel>
<FormDescription>Allow anyone to see and offer on your loan</FormDescription>
</div>
Expand All @@ -61,8 +61,8 @@ export function PreferencesSection({ control }: PreferencesSectionProps) {
/>
</div>

<div className="flex items-center justify-between">
<div className="space-y-0.5">
<div className="flex flex-col gap-3 rounded-md border border-subtle p-3 sm:flex-row sm:items-center sm:justify-between">
<div className="min-w-0 space-y-0.5">
<FormLabel>Negotiable Terms</FormLabel>
<FormDescription>Allow offerers to propose different terms</FormDescription>
</div>
Expand Down
16 changes: 9 additions & 7 deletions src/components/public/PublicEntityDetailPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -307,17 +307,19 @@ export default async function PublicEntityDetailPage({
className="mb-4"
/>
<div className="flex items-start justify-between">
<div className="flex items-center gap-4">
<div className="flex min-w-0 flex-col gap-4 sm:flex-row sm:items-center">
{config.renderHeaderIcon?.(entity) ?? (
<div
className={`w-16 h-16 ${theme.bg} rounded-lg flex items-center justify-center`}
className={`h-14 w-14 flex-shrink-0 ${theme.bg} rounded-lg flex items-center justify-center sm:h-16 sm:w-16`}
>
<Icon className={`w-8 h-8 ${theme.icon}`} />
<Icon className={`h-7 w-7 sm:h-8 sm:w-8 ${theme.icon}`} />
</div>
)}
<div>
<h1 className="text-2xl sm:text-3xl font-bold text-fg-primary">{entity.title}</h1>
<div className="flex items-center gap-3 mt-2">
<div className="min-w-0">
<h1 className="break-words text-2xl font-bold text-fg-primary sm:text-3xl">
{entity.title}
</h1>
<div className="mt-2 flex flex-wrap items-center gap-2 sm:gap-3">
{entity.status && (
<Badge variant="default" className="capitalize">
{entity.status}
Expand Down Expand Up @@ -444,7 +446,7 @@ function StickyBar({ href, label }: { href: string; label: string }) {
// to the page wrapper) reserves matching scroll-bottom room.
return (
<div
className={`md:hidden fixed inset-x-0 oc-above-mobile-nav ${Z_INDEX_CLASSES.MOBILE_ACTION_BAR} border-t border-subtle bg-surface-base/95 backdrop-blur supports-[backdrop-filter]:bg-surface-base/80 px-4 py-3 shadow-lg`}
className={`md:hidden fixed inset-x-0 oc-above-mobile-nav ${Z_INDEX_CLASSES.MOBILE_ACTION_BAR} border-t border-subtle bg-surface-base/95 backdrop-blur supports-[backdrop-filter]:bg-surface-base/80 px-4 py-3 shadow-sm`}
>
<a
href={href}
Expand Down
Loading
Loading