MotorSignal-App/website/components/founder-portal/attention-card.tsx

253 lines
11 KiB
TypeScript

'use client';
import React from 'react';
import { ClubMember, ClubUpcomingRide, UserPortalPermissions } from './types';
import { EmptyState } from './empty-state';
interface AttentionSectionProps {
pendingApplications: ClubMember[];
upcomingRides: ClubUpcomingRide[];
permissions: UserPortalPermissions;
onApproveApplication?: (uid: string) => void;
onReviewApplication?: (uid: string) => void;
onAssignSweep?: (rideId: string) => void;
onMarkChecked?: () => void;
}
export function AttentionSection({
pendingApplications,
upcomingRides,
permissions,
onApproveApplication,
onReviewApplication,
onAssignSweep,
onMarkChecked,
}: AttentionSectionProps) {
// Find any ride needing assignment
const rideNeedingSweep = upcomingRides.find(
(r) => r.sweepStatus === 'needs_assignment' || r.sweepStatus === 'vacant'
);
const pendingAppsCount = pendingApplications.length;
const totalPendingActions = (pendingAppsCount > 0 ? 1 : 0) + (rideNeedingSweep ? 1 : 0);
return (
<section className="rounded-2xl glass-card border border-brand-border/60 p-5 sm:p-6 space-y-5 shadow-lg">
{/* Header */}
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<span
className={`w-2 h-2 rounded-full ${
totalPendingActions > 0 ? 'bg-error animate-pulse' : 'bg-brand-cyan'
}`}
/>
<h2 className="font-headline text-base font-bold text-white tracking-wide">
Attention Required
</h2>
</div>
<div className="flex items-center gap-2">
<span className="font-mono text-xs text-slate-400">
{totalPendingActions} pending {totalPendingActions === 1 ? 'action' : 'actions'}
</span>
{onMarkChecked && (
<button
onClick={onMarkChecked}
className="px-2.5 py-1 rounded-lg bg-surface-container hover:bg-surface-container-high text-slate-300 hover:text-white font-mono text-xs border border-brand-border/60 transition-colors"
>
Mark Checked
</button>
)}
</div>
</div>
{/* 3 Triage Cards Grid */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4">
{/* Card 1: Membership Applications */}
<div className="rounded-xl bg-surface-container/60 border border-brand-border/60 p-4 sm:p-5 flex flex-col justify-between shadow-md">
<div>
<div className="flex items-center justify-between pb-2.5 border-b border-brand-border/40">
<div className="flex items-center gap-1.5">
<span className="material-symbols-outlined text-[18px] text-brand-cyan">
person_add
</span>
<span className="font-body text-xs sm:text-sm font-semibold text-white">
Membership Applications
</span>
</div>
{pendingAppsCount > 0 ? (
<span className="px-2 py-0.5 rounded-full bg-error-container text-on-error-container font-mono text-[10px] font-semibold border border-error/30">
{pendingAppsCount} Pending
</span>
) : (
<span className="font-mono text-[10px] text-slate-400 bg-surface-container px-2 py-0.5 rounded-full border border-brand-border/40">0 Pending</span>
)}
</div>
<p className="font-body text-xs text-slate-400 mt-2 mb-3">
Membership applications awaiting review.
</p>
{pendingAppsCount === 0 ? (
<EmptyState
icon="how_to_reg"
title="No Pending Applications"
description="No membership applications currently require review."
className="py-4"
/>
) : (
<div className="space-y-2">
{pendingApplications.slice(0, 3).map((app) => (
<div
key={app.uid}
className="p-2.5 rounded-lg bg-surface-container-high border border-brand-border/60 flex items-center justify-between gap-2"
>
<div className="min-w-0">
<div className="font-body text-xs font-semibold text-white truncate">
{app.displayName ?? 'New Rider'}
</div>
<div className="font-mono text-[10px] text-slate-400">
{app.requestedAt ?? app.joinedAt ?? 'Recently'}
</div>
</div>
<div className="flex items-center gap-1.5 shrink-0">
{permissions.canApproveApplications && (
<button
onClick={() => onApproveApplication?.(app.uid)}
className="px-2.5 py-1 rounded-lg bg-primary-container text-on-primary-container font-bold text-[11px] hover:brightness-110 shadow-[0_0_8px_rgba(0,242,254,0.2)] transition-all cursor-pointer"
>
Approve
</button>
)}
<button
onClick={() => onReviewApplication?.(app.uid)}
className="px-2 py-1 rounded-lg bg-surface-container hover:bg-surface-container-high text-slate-300 font-mono text-[10px] border border-brand-border/60 transition-colors cursor-pointer"
>
Review
</button>
</div>
</div>
))}
</div>
)}
</div>
<div className="mt-3 pt-2 border-t border-brand-border/40 flex items-center justify-between text-slate-400 font-mono text-[10px]">
<span>Triage Status</span>
<span>{pendingAppsCount === 0 ? 'All Cleared' : `${pendingAppsCount} Actionable`}</span>
</div>
</div>
{/* Card 2: Moderation Flag / Wall Posts (Preserving deferred backend architecture) */}
<div className="rounded-xl bg-surface-container/60 border border-brand-border/60 p-4 sm:p-5 flex flex-col justify-between shadow-md">
<div>
<div className="flex items-center justify-between pb-2.5 border-b border-brand-border/40">
<div className="flex items-center gap-1.5">
<span className="material-symbols-outlined text-[17px] text-amber-400">gavel</span>
<span className="font-body text-xs sm:text-sm font-semibold text-white">
Reported Club Wall Post
</span>
</div>
<span className="font-mono text-[10px] text-slate-400 bg-surface-container px-2 py-0.5 rounded-full border border-brand-border/40">Deferred</span>
</div>
<p className="font-body text-xs text-slate-400 mt-2 mb-3">
Club Wall moderation and content flagging module.
</p>
<EmptyState
icon="verified"
title="No Reported Posts"
description="No content flags pending. Club Wall moderation backend is scheduled for future release."
className="py-4"
/>
</div>
<div className="mt-3 pt-2 border-t border-brand-border/40 flex items-center justify-between text-slate-400 font-mono text-[10px]">
<span>Moderation Queue</span>
<span>Cleared</span>
</div>
</div>
{/* Card 3: Upcoming Ride Assignment */}
<div className="rounded-xl bg-surface-container/60 border border-brand-border/60 p-4 sm:p-5 flex flex-col justify-between shadow-md">
<div>
<div className="flex items-center justify-between pb-2.5 border-b border-brand-border/40">
<div className="flex items-center gap-1.5">
<span className="material-symbols-outlined text-[17px] text-brand-cyan">
assignment_ind
</span>
<span className="font-body text-xs sm:text-sm font-semibold text-white">
Upcoming Ride Assignment
</span>
</div>
{rideNeedingSweep ? (
<span className="px-2 py-0.5 rounded-full bg-brand-cyan/15 text-brand-cyan font-mono text-[10px] font-semibold border border-brand-cyan/30">
Action Needed
</span>
) : (
<span className="font-mono text-[10px] text-slate-400 bg-surface-container px-2 py-0.5 rounded-full border border-brand-border/40">Assigned</span>
)}
</div>
<p className="font-body text-xs text-slate-400 mt-2 mb-3">
Safety position check for scheduled group rides:
</p>
{rideNeedingSweep ? (
<div className="rounded bg-surface-container-high border border-outline-variant/60 p-2.5 space-y-2">
<div className="flex items-center justify-between">
<span className="font-body text-xs text-on-surface font-semibold truncate max-w-[180px]">
{rideNeedingSweep.title}
</span>
<span className="font-mono text-[10px] text-primary shrink-0">
{rideNeedingSweep.scheduledStartAt.split('·')[0].trim()}
</span>
</div>
<div className="grid grid-cols-2 gap-1.5 font-mono text-[11px] text-outline">
<div>
Riders Going: <span className="text-on-surface">{rideNeedingSweep.confirmedCount}</span>
</div>
<div>
Road Captain: <span className="text-on-surface">{rideNeedingSweep.roadCaptainName}</span>
</div>
<div className="col-span-2">
Sweep: <span className="text-error font-medium">Vacant</span>
</div>
</div>
<div className="p-1.5 rounded bg-surface-container-lowest/80 font-body text-[11px] text-on-surface-variant border border-outline-variant/40">
Sweep position is currently unassigned for this ride.
</div>
</div>
) : (
<EmptyState
icon="check_circle"
title="Rosters Assigned"
description="All scheduled rides have designated Road Captain and Sweep positions."
className="py-4"
/>
)}
</div>
<div className="mt-3 pt-2">
{rideNeedingSweep && permissions.canPlanRides ? (
<button
onClick={() => onAssignSweep?.(rideNeedingSweep.id)}
className="w-full h-8 rounded-lg bg-secondary-fixed text-on-secondary-fixed font-body text-xs font-bold hover:brightness-110 transition-all flex items-center justify-center gap-1.5 shadow-sm cursor-pointer"
>
<span className="material-symbols-outlined text-[16px]">person_pin_circle</span>
<span>Assign Sweep</span>
</button>
) : (
<div className="font-mono text-[10px] text-outline text-right">
Positions Stable
</div>
)}
</div>
</div>
</div>
</section>
);
}