feat: add recent plans history to homepage
This commit is contained in:
@@ -8,6 +8,7 @@ import { Button } from "@/components/ui/button"
|
|||||||
import { PlanLoginForm } from "@/components/plan-login-form"
|
import { PlanLoginForm } from "@/components/plan-login-form"
|
||||||
import { PlanDashboard } from "./_components/plan-dashboard"
|
import { PlanDashboard } from "./_components/plan-dashboard"
|
||||||
import { getDictionary } from "@/get-dictionary"
|
import { getDictionary } from "@/get-dictionary"
|
||||||
|
import { PlanTracker } from "@/components/plan-tracker"
|
||||||
|
|
||||||
export default async function DashboardPage({
|
export default async function DashboardPage({
|
||||||
params
|
params
|
||||||
@@ -39,6 +40,7 @@ export default async function DashboardPage({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="flex min-h-screen flex-col items-center p-4">
|
<main className="flex min-h-screen flex-col items-center p-4">
|
||||||
|
<PlanTracker planId={plan.id} title={plan.title} />
|
||||||
<div className="w-full max-w-4xl space-y-6">
|
<div className="w-full max-w-4xl space-y-6">
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<Button variant="ghost" size="sm" asChild className="w-fit -ml-2 text-muted-foreground">
|
<Button variant="ghost" size="sm" asChild className="w-fit -ml-2 text-muted-foreground">
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import Image from "next/image";
|
|||||||
import { CreatePlanForm } from "@/components/create-plan-form";
|
import { CreatePlanForm } from "@/components/create-plan-form";
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import { getDictionary } from "@/get-dictionary";
|
import { getDictionary } from "@/get-dictionary";
|
||||||
|
import { RecentPlans } from "@/components/recent-plans";
|
||||||
|
|
||||||
export default async function Home({
|
export default async function Home({
|
||||||
params,
|
params,
|
||||||
@@ -32,6 +33,8 @@ export default async function Home({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<RecentPlans lang={lang} dict={dict.home.recentPlans} />
|
||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>{dict.home.createPlan}</CardTitle>
|
<CardTitle>{dict.home.createPlan}</CardTitle>
|
||||||
|
|||||||
35
components/plan-tracker.tsx
Normal file
35
components/plan-tracker.tsx
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { useEffect } from "react"
|
||||||
|
|
||||||
|
export function PlanTracker({ planId, title }: { planId: string, title: string }) {
|
||||||
|
useEffect(() => {
|
||||||
|
const stored = localStorage.getItem("csp_recent_plans")
|
||||||
|
let plans: { id: string, title: string, lastVisited: number }[] = []
|
||||||
|
|
||||||
|
if (stored) {
|
||||||
|
try {
|
||||||
|
plans = JSON.parse(stored)
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove existing entry for this plan
|
||||||
|
plans = plans.filter(p => p.id !== planId)
|
||||||
|
|
||||||
|
// Add to top
|
||||||
|
plans.unshift({
|
||||||
|
id: planId,
|
||||||
|
title: title,
|
||||||
|
lastVisited: Date.now()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Keep max 5
|
||||||
|
plans = plans.slice(0, 5)
|
||||||
|
|
||||||
|
localStorage.setItem("csp_recent_plans", JSON.stringify(plans))
|
||||||
|
}, [planId, title])
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
76
components/recent-plans.tsx
Normal file
76
components/recent-plans.tsx
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { useEffect, useState } from "react"
|
||||||
|
import Link from "next/link"
|
||||||
|
import { History, ChevronRight, X } from "lucide-react"
|
||||||
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
|
|
||||||
|
type RecentPlan = {
|
||||||
|
id: string
|
||||||
|
title: string
|
||||||
|
lastVisited: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export function RecentPlans({ lang, dict }: { lang: string, dict: { title: string, noPlans: string, clear: string } }) {
|
||||||
|
const [plans, setPlans] = useState<RecentPlan[]>([])
|
||||||
|
const [mounted, setMounted] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setMounted(true)
|
||||||
|
const stored = localStorage.getItem("csp_recent_plans")
|
||||||
|
if (stored) {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(stored)
|
||||||
|
setPlans(parsed.sort((a: RecentPlan, b: RecentPlan) => b.lastVisited - a.lastVisited))
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to parse recent plans", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const removePlan = (id: string, e: React.MouseEvent) => {
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
const newPlans = plans.filter(p => p.id !== id)
|
||||||
|
setPlans(newPlans)
|
||||||
|
localStorage.setItem("csp_recent_plans", JSON.stringify(newPlans))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mounted || plans.length === 0) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="pb-3">
|
||||||
|
<CardTitle className="text-base font-medium flex items-center gap-2">
|
||||||
|
<History className="w-4 h-4" />
|
||||||
|
{dict.title}
|
||||||
|
</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="grid gap-2">
|
||||||
|
{plans.map((plan) => (
|
||||||
|
<Link
|
||||||
|
key={plan.id}
|
||||||
|
href={`/${lang}/dashboard/${plan.id}`}
|
||||||
|
className="group flex items-center justify-between p-3 rounded-lg border bg-card hover:bg-accent/50 transition-colors"
|
||||||
|
>
|
||||||
|
<div className="font-medium truncate mr-4">
|
||||||
|
{plan.title}
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2 text-muted-foreground">
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
className="h-6 w-6 opacity-0 group-hover:opacity-100 transition-opacity"
|
||||||
|
onClick={(e) => removePlan(plan.id, e)}
|
||||||
|
>
|
||||||
|
<X className="w-3.5 h-3.5" />
|
||||||
|
</Button>
|
||||||
|
<ChevronRight className="w-4 h-4" />
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -3,7 +3,12 @@
|
|||||||
"title": "Katzen-Sitting-Planer",
|
"title": "Katzen-Sitting-Planer",
|
||||||
"description": "Koordiniere die Pflege deiner Vierbeiner, während du weg bist.",
|
"description": "Koordiniere die Pflege deiner Vierbeiner, während du weg bist.",
|
||||||
"createPlan": "Neuen Plan erstellen",
|
"createPlan": "Neuen Plan erstellen",
|
||||||
"createPlanDesc": "Gib deinem Plan einen Namen, wähle deine Reisedaten und setze ein Gruppen-Passwort."
|
"createPlanDesc": "Gib deinem Plan einen Namen, wähle deine Reisedaten und setze ein Gruppen-Passwort.",
|
||||||
|
"recentPlans": {
|
||||||
|
"title": "Zuletzt besuchte Pläne",
|
||||||
|
"noPlans": "Keine Pläne",
|
||||||
|
"clear": "Leeren"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"createPlanForm": {
|
"createPlanForm": {
|
||||||
"title": "Titel des Plans",
|
"title": "Titel des Plans",
|
||||||
|
|||||||
@@ -3,7 +3,12 @@
|
|||||||
"title": "Cat Sitting Planner",
|
"title": "Cat Sitting Planner",
|
||||||
"description": "Coordinate care for your furry friends while you're away.",
|
"description": "Coordinate care for your furry friends while you're away.",
|
||||||
"createPlan": "Create a New Plan",
|
"createPlan": "Create a New Plan",
|
||||||
"createPlanDesc": "Give your plan a title, select your travel dates and set a group password."
|
"createPlanDesc": "Give your plan a title, select your travel dates and set a group password.",
|
||||||
|
"recentPlans": {
|
||||||
|
"title": "Recently Visited Plans",
|
||||||
|
"noPlans": "No recent plans",
|
||||||
|
"clear": "Clear"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"createPlanForm": {
|
"createPlanForm": {
|
||||||
"title": "Plan Title",
|
"title": "Plan Title",
|
||||||
|
|||||||
Reference in New Issue
Block a user