feat: complete Phase 3 — advanced features for Casera web app

Adds sharing (residence share codes, join, user management, .casera file
export/import), subscription status with feature comparison, notification
preferences with bell icon, profile settings (edit info, change password,
theme picker, delete account), onboarding wizard with create/join paths,
enhanced dashboard with stats cards, Recharts completion chart, recent
activity feed, and task report PDF download.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-03-03 09:31:29 -06:00
commit 5a50d77515
183 changed files with 34450 additions and 0 deletions
@@ -0,0 +1,106 @@
"use client";
import { useState } from "react";
import { Copy, Check, RefreshCw } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { useShareCode, useGenerateShareCode } from "@/lib/hooks/use-sharing";
interface ShareCodeDisplayProps {
residenceId: number;
}
export function ShareCodeDisplay({ residenceId }: ShareCodeDisplayProps) {
const { data, isLoading } = useShareCode(residenceId);
const generateCode = useGenerateShareCode(residenceId);
const [copied, setCopied] = useState(false);
const shareCode = data?.share_code;
async function handleCopy() {
if (!shareCode) return;
await navigator.clipboard.writeText(shareCode.code);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
}
function handleGenerate() {
generateCode.mutate();
}
if (isLoading) {
return (
<Card>
<CardHeader>
<CardTitle>Share Code</CardTitle>
<CardDescription>Loading...</CardDescription>
</CardHeader>
</Card>
);
}
return (
<Card>
<CardHeader>
<CardTitle>Share Code</CardTitle>
<CardDescription>
Share this code with others to invite them to your residence.
</CardDescription>
</CardHeader>
<CardContent>
{shareCode ? (
<div className="space-y-4">
<div className="flex items-center gap-3">
<code className="flex-1 rounded-lg border bg-muted px-4 py-3 text-center text-2xl font-mono font-bold tracking-widest">
{shareCode.code}
</code>
<Button
variant="outline"
size="icon"
onClick={handleCopy}
title="Copy to clipboard"
>
{copied ? (
<Check className="size-4 text-green-600" />
) : (
<Copy className="size-4" />
)}
</Button>
</div>
<p className="text-sm text-muted-foreground">
Expires{" "}
{new Date(shareCode.expires_at).toLocaleDateString(undefined, {
year: "numeric",
month: "long",
day: "numeric",
hour: "numeric",
minute: "2-digit",
})}
</p>
<Button
variant="outline"
size="sm"
onClick={handleGenerate}
disabled={generateCode.isPending}
>
<RefreshCw className="size-4 mr-2" />
{generateCode.isPending ? "Generating..." : "Generate New Code"}
</Button>
</div>
) : (
<div className="text-center py-4">
<p className="text-sm text-muted-foreground mb-4">
No active share code. Generate one to invite others.
</p>
<Button
onClick={handleGenerate}
disabled={generateCode.isPending}
>
{generateCode.isPending ? "Generating..." : "Generate Share Code"}
</Button>
</div>
)}
</CardContent>
</Card>
);
}