fiddy/apps/web/features/entries/components/schedules-list.tsx
Nico f8e426542d
Some checks failed
Build & Deploy Fiddy (Dokploy) / build (push) Has been cancelled
Build & Deploy Fiddy (Dokploy) / deploy (push) Has been cancelled
feat: implement schedules pivot, scheduler service, and dokploy deploy flow
2026-02-15 17:10:58 -08:00

86 lines
4.1 KiB
TypeScript

"use client";
import type { Schedule } from "@/lib/shared/types";
type SchedulesListProps = {
activeGroupId: number | null;
loading: boolean;
schedules: Schedule[];
visibleSchedules: Schedule[];
activeFilterCount: number;
onOpenDetails: (schedule: Schedule, index: number) => void;
onClearFilters: () => void;
};
export default function SchedulesList({
activeGroupId,
loading,
schedules,
visibleSchedules,
activeFilterCount,
onOpenDetails,
onClearFilters
}: SchedulesListProps) {
return (
<div className="mt-3 space-y-2">
{!activeGroupId ? (
<div className="text-sm text-muted">Select a group to view schedules.</div>
) : loading ? (
<div className="space-y-2">
{[0, 1, 2].map(row => (
<div key={row} className="rounded-lg border border-accent-weak bg-panel px-3 py-3">
<div className="animate-pulse space-y-2">
<div className="h-4 w-28 rounded bg-surface" />
<div className="h-3 w-40 rounded bg-surface" />
<div className="h-3 w-36 rounded bg-surface" />
</div>
</div>
))}
</div>
) : schedules.length ? (
visibleSchedules.length ? (
visibleSchedules.map((schedule, index) => (
<div
key={schedule.id}
className="flex min-h-[84px] cursor-pointer flex-col justify-between gap-2 rounded-lg border border-accent-weak bg-panel px-3 py-2 text-sm transition hover:border-accent hover:bg-accent-soft"
onClick={() => onOpenDetails(schedule, index)}
>
<div className="flex items-start justify-between gap-3">
<div className="flex items-center gap-2">
<div className="text-base font-semibold">${schedule.amountDollars.toFixed(2)}</div>
<div className={`rounded-full border px-2 py-0.5 text-[10px] ${schedule.isActive ? "border-green-400/60 bg-green-500/10 text-green-200" : "border-amber-400/60 bg-amber-500/10 text-amber-200"}`}>
{schedule.isActive ? "Active" : "Paused"}
</div>
</div>
<div className="text-xs text-muted">Next: {schedule.nextRunOn}</div>
</div>
<div className="flex flex-wrap items-center gap-1.5">
{(schedule.tags || []).length ? (
schedule.tags.map(tag => (
<span key={`${schedule.id}-${tag}`} className="rounded-full border border-accent-weak bg-accent-soft px-2 py-0.5 text-xs">
#{tag}
</span>
))
) : (
<span className="rounded-full border border-accent-weak px-2 py-0.5 text-xs text-soft">No tags</span>
)}
</div>
</div>
))
) : (
<div className="space-y-2 text-sm text-muted">
<div>No matching schedules.</div>
{activeFilterCount ? (
<button type="button" className="rounded-lg btn-outline-accent px-3 py-1 text-xs" onClick={onClearFilters}>
Clear filters
</button>
) : null}
</div>
)
) : (
<div className="text-sm text-muted">No schedules yet.</div>
)}
</div>
);
}