Skip to content

Commit ee56970

Browse files
committed
feat(agenda): add AgendaDetails component and remove AgendaDialog for improved agenda management
1 parent 1adfa5c commit ee56970

File tree

4 files changed

+134
-108
lines changed

4 files changed

+134
-108
lines changed
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
'use client';
2+
3+
import type { MeetTogetherPlan } from '@tuturuuu/types/primitives/MeetTogetherPlan';
4+
import { Button } from '@tuturuuu/ui/button';
5+
import { ClipboardList, Pencil, Plus } from '@tuturuuu/ui/icons';
6+
import { RichTextEditor } from '@tuturuuu/ui/text-editor/editor';
7+
import { type JSONContent } from '@tuturuuu/ui/tiptap';
8+
import { useTranslations } from 'next-intl';
9+
import { useRouter } from 'next/navigation';
10+
import { useCallback, useState } from 'react';
11+
12+
interface AgendaDetailsProps {
13+
plan: MeetTogetherPlan;
14+
}
15+
16+
export default function AgendaDetails({ plan }: AgendaDetailsProps) {
17+
const t = useTranslations('meet-together');
18+
const router = useRouter();
19+
20+
const [editContent, setEditContent] = useState<JSONContent | null>(
21+
plan.agenda_content || null
22+
);
23+
const [isEditing, setIsEditing] = useState(false);
24+
const [isLoading, setIsLoading] = useState(false);
25+
26+
const handleEdit = useCallback(() => {
27+
setIsEditing(true);
28+
setEditContent(plan.agenda_content || null);
29+
}, [plan.agenda_content]);
30+
31+
const handleCancel = useCallback(() => {
32+
setIsEditing(false);
33+
setEditContent(plan.agenda_content || null);
34+
}, [plan.agenda_content]);
35+
36+
const handleSave = useCallback(async () => {
37+
if (!plan.id) return;
38+
39+
setIsLoading(true);
40+
try {
41+
const data = {
42+
agenda_content: editContent,
43+
};
44+
45+
const res = await fetch(`/api/meet-together/plans/${plan.id}`, {
46+
method: 'PUT',
47+
body: JSON.stringify(data),
48+
});
49+
50+
if (res.ok) {
51+
setIsEditing(false);
52+
router.refresh();
53+
} else {
54+
console.error('Failed to save agenda');
55+
}
56+
} catch (error) {
57+
console.error('Error saving agenda:', error);
58+
} finally {
59+
setIsLoading(false);
60+
}
61+
}, [plan.id, editContent, router]);
62+
63+
const handleContentChange = useCallback((content: JSONContent) => {
64+
setEditContent(content);
65+
}, []);
66+
67+
return (
68+
<div className="w-full space-y-8">
69+
<div className="flex flex-col items-center justify-between gap-4 md:flex-row">
70+
<div className="space-y-4">
71+
<p className="text-4xl font-semibold">{t('agenda')}</p>
72+
<p className="text-md text-muted-foreground">
73+
{t('agenda_description')}
74+
</p>
75+
</div>
76+
{isEditing ? (
77+
<div className="flex justify-center gap-2">
78+
<Button
79+
onClick={handleCancel}
80+
variant="outline"
81+
size="lg"
82+
disabled={isLoading}
83+
>
84+
Cancel
85+
</Button>
86+
<Button onClick={handleSave} size="lg" disabled={isLoading}>
87+
{isLoading ? 'Saving...' : 'Save'}
88+
</Button>
89+
</div>
90+
) : plan.agenda_content ? (
91+
<Button onClick={handleEdit} variant="outline" size="lg">
92+
<Pencil size={16} />
93+
Edit
94+
</Button>
95+
) : (
96+
<Button onClick={handleEdit} variant="default" size="lg">
97+
<Plus size={16} />
98+
Add Agenda
99+
</Button>
100+
)}
101+
</div>
102+
103+
{plan.agenda_content ? (
104+
<RichTextEditor
105+
content={isEditing ? editContent : plan.agenda_content}
106+
onChange={isEditing ? handleContentChange : undefined}
107+
readOnly={!isEditing}
108+
className="max-h-screen w-full"
109+
/>
110+
) : (
111+
<div className="flex h-96 w-full items-center justify-center">
112+
<div className="flex flex-col items-center space-y-4 text-center">
113+
<div className="rounded-full bg-muted p-6">
114+
<ClipboardList size={48} className="text-muted-foreground" />
115+
</div>
116+
<div className="space-y-2">
117+
<h3 className="text-lg font-medium">No Agenda Content Yet</h3>
118+
<p className="max-w-md text-sm text-muted-foreground">
119+
Start organizing your meeting by creating a structured outline
120+
to keep everyone on track to make your meeting more productive.
121+
</p>
122+
</div>
123+
</div>
124+
</div>
125+
)}
126+
</div>
127+
);
128+
}

apps/web/src/app/[locale]/(marketing)/meet-together/plans/[planId]/agenda-dialog.tsx

Lines changed: 0 additions & 40 deletions
This file was deleted.

apps/web/src/app/[locale]/(marketing)/meet-together/plans/[planId]/edit-plan-dialog.tsx

Lines changed: 1 addition & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,6 @@ import { Pencil } from '@tuturuuu/ui/icons';
3636
import { Input } from '@tuturuuu/ui/input';
3737
import { zodResolver } from '@tuturuuu/ui/resolvers';
3838
import { Separator } from '@tuturuuu/ui/separator';
39-
import { RichTextEditor } from '@tuturuuu/ui/text-editor/editor';
40-
import type { JSONContent } from '@tuturuuu/ui/tiptap';
41-
import { Sparkles } from 'lucide-react';
4239
import { useTranslations } from 'next-intl';
4340
import { useRouter } from 'next/navigation';
4441
import { useState } from 'react';
@@ -51,7 +48,6 @@ interface Props {
5148
const FormSchema = z.object({
5249
name: z.string(),
5350
is_public: z.boolean().optional(),
54-
agenda_content: z.custom<JSONContent>().optional(),
5551
});
5652

5753
type FormData = z.infer<typeof FormSchema>;
@@ -70,7 +66,6 @@ export default function EditPlanDialog({ plan }: Props) {
7066
values: {
7167
name: plan.name || t('meet-together.untitled_plan'),
7268
is_public: true,
73-
agenda_content: plan.agenda_content ?? undefined,
7469
},
7570
});
7671

@@ -80,7 +75,6 @@ export default function EditPlanDialog({ plan }: Props) {
8075
const disabled = !isValid || isSubmitting;
8176

8277
const handleSubmit = async (data: FormData) => {
83-
console.log(data);
8478
setUpdating(true);
8579

8680
const hasError = false;
@@ -145,7 +139,7 @@ export default function EditPlanDialog({ plan }: Props) {
145139
</Button>
146140
</DialogTrigger>
147141
<DialogContent
148-
className="max-h-[90vh] overflow-y-auto sm:max-w-[800px]"
142+
className="sm:max-w-[425px]"
149143
onOpenAutoFocus={(e) => e.preventDefault()}
150144
>
151145
<DialogHeader>
@@ -178,49 +172,6 @@ export default function EditPlanDialog({ plan }: Props) {
178172
)}
179173
/>
180174

181-
<Separator className="my-6" />
182-
183-
{/* Extra Features Section */}
184-
<div className="space-y-4">
185-
<div className="flex items-center gap-2">
186-
<Sparkles className="h-4 w-4 text-purple-500" />
187-
<h3 className="text-sm font-semibold text-foreground">
188-
Extra Features
189-
</h3>
190-
</div>
191-
<p className="text-xs text-muted-foreground">
192-
Enhance your meeting plan with additional features to make
193-
coordination easier.
194-
</p>
195-
196-
<FormField
197-
control={form.control}
198-
name="agenda_content"
199-
render={({ field }) => (
200-
<FormItem>
201-
<FormLabel>{t('meet-together.agenda')}</FormLabel>
202-
<FormControl>
203-
<RichTextEditor
204-
content={field.value || null}
205-
onChange={field.onChange}
206-
readOnly={false}
207-
titlePlaceholder={t(
208-
'meet-together.agenda_title_placeholder'
209-
)}
210-
writePlaceholder={t(
211-
'meet-together.agenda_content_placeholder'
212-
)}
213-
saveButtonLabel={t('meet-together.save_agenda')}
214-
savedButtonLabel={t('meet-together.agenda_saved')}
215-
className="h-64"
216-
/>
217-
</FormControl>
218-
<FormMessage />
219-
</FormItem>
220-
)}
221-
/>
222-
</div>
223-
224175
<DialogFooter>
225176
<div className="grid w-full gap-2">
226177
<Button

apps/web/src/app/[locale]/(marketing)/meet-together/plans/[planId]/plan-details-client.tsx

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
11
'use client';
22

3-
import AgendaDialog from './agenda-dialog';
3+
import AgendaDetails from './agenda-details';
44
import AllAvailabilities from './all-availabilities';
55
import EditPlanDialog from './edit-plan-dialog';
66
import PlanLogin from './plan-login';
77
import PlanUserFilter from './plan-user-filter';
88
import UtilityButtons from './utility-buttons';
99
import type { MeetTogetherPlan } from '@tuturuuu/types/primitives/MeetTogetherPlan';
1010
import type { User } from '@tuturuuu/types/primitives/User';
11-
import { Button } from '@tuturuuu/ui/button';
12-
import { FileText } from '@tuturuuu/ui/icons';
1311
import { Separator } from '@tuturuuu/ui/separator';
1412
import html2canvas from 'html2canvas-pro';
15-
import { useTranslations } from 'next-intl';
1613
import { useTheme } from 'next-themes';
1714
import { useCallback } from 'react';
1815

@@ -44,7 +41,6 @@ export default function PlanDetailsClient({
4441
timeblocks,
4542
}: PlanDetailsClientProps) {
4643
const { resolvedTheme } = useTheme();
47-
const t = useTranslations('meet-together');
4844

4945
const downloadAsPNG = useCallback(async () => {
5046
const element = document.getElementById('plan-ref');
@@ -91,19 +87,6 @@ export default function PlanDetailsClient({
9187
<p className="my-4 flex max-w-xl items-center gap-2 text-center text-2xl leading-tight! font-semibold md:mb-4 lg:text-3xl">
9288
{plan.name} <EditPlanDialog plan={plan} />
9389
</p>
94-
{plan.agenda_content && (
95-
<div className="mb-4">
96-
<AgendaDialog
97-
agendaContent={plan.agenda_content}
98-
trigger={
99-
<Button variant="outline" size="sm" className="gap-2">
100-
<FileText size={16} />
101-
{t('agenda')}
102-
</Button>
103-
}
104-
/>
105-
</div>
106-
)}
10790
<div className="mt-8 grid w-full items-center justify-between gap-4 md:grid-cols-2">
10891
<PlanLogin
10992
plan={plan}
@@ -112,6 +95,10 @@ export default function PlanDetailsClient({
11295
/>
11396
<AllAvailabilities plan={plan} timeblocks={timeblocks} />
11497
</div>
98+
99+
<Separator className="my-8" />
100+
101+
<AgendaDetails plan={plan} />
115102
</div>
116103
</div>
117104
{users.length > 0 && (

0 commit comments

Comments
 (0)