diff --git a/src/app/team/phan/page.tsx b/src/app/team/phan/page.tsx index 3dd6861..67393c4 100644 --- a/src/app/team/phan/page.tsx +++ b/src/app/team/phan/page.tsx @@ -1,26 +1,60 @@ "use client"; + import { useState } from "react"; +import { GroupEditModal } from "@/components/groups/group-edit-modal"; +import { Button } from "@/components/ui/button"; + +const mockGroup = { + id: 1, + name: "Friends", + description: "People I keep in touch with.", + members: [ + { memberId: 1, ownername: "Alice Johnson" }, + { memberId: 2, ownername: "Bob Smith" }, + { memberId: 3, ownername: "Charlie Brown" }, + { memberId: 4, ownername: "Diana Prince" }, + { memberId: 5, ownername: "Ethan Hunt" }, + { memberId: 6, ownername: "Fiona Apple" }, + { memberId: 7, ownername: "George Lucas" }, + { memberId: 8, ownername: "Hannah Montana" }, + { memberId: 9, ownername: "Isaac Newton" }, + { memberId: 10, ownername: "Julia Child" }, + ], + memberCount: 10, +}; export default function PhanPage() { - const [counter, setCounter] = useState(0); + const [defaultOpen, setDefaultOpen] = useState(false); + const [submittingOpen, setSubmittingOpen] = useState(false); + return ( -
-
-
-

Sam Phan

-

Developer

-

- Fun Fact: - I have recently finished Season 1 of After Life (Netflix original). -

-
- -
+
+

Group Edit Modal Preview

+ + + + + { + alert(JSON.stringify(data, null, 2)); + setDefaultOpen(false); + }} + onDelete={() => alert("Delete clicked")} + onAddMembers={() => alert("Add members clicked")} + /> + + {}} + onDelete={() => {}} + onAddMembers={() => {}} + isSubmitting + />
); } diff --git a/src/components/groups/group-edit-modal.tsx b/src/components/groups/group-edit-modal.tsx new file mode 100644 index 0000000..b6d565c --- /dev/null +++ b/src/components/groups/group-edit-modal.tsx @@ -0,0 +1,188 @@ +"use client"; + +import { useRef, useState } from "react"; +import { Loader2, Plus } from "lucide-react"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Textarea } from "@/components/ui/textarea"; +import { Avatar, AvatarFallback } from "@/components/ui/avatar"; +import { getAvatarColor, getInitials } from "@/utils/avatar"; + +interface GroupEditModalProps { + open: boolean; + onOpenChange: (open: boolean) => void; + group: { + id: number; + name: string; + description: string | null; + members: Array<{ memberId: number; ownername: string }>; + memberCount: number; + }; + onSave: (data: { name: string; description: string | null }) => void; + onDelete: () => void; + onAddMembers: () => void; + isSubmitting?: boolean; +} + +export function GroupEditModal({ + open, + onOpenChange, + group, + onSave, + onDelete, + onAddMembers, + isSubmitting = false, +}: GroupEditModalProps) { + const [newName, setNewName] = useState(group.name); + const [newDescription, setNewDescription] = useState(group.description ?? ""); + const [error, setError] = useState(""); + const nameRef = useRef(null); + + const handleOpenChange = (nextOpen: boolean) => { + if (isSubmitting) return; + if (nextOpen) { + setNewName(group.name); + setNewDescription(group.description ?? ""); + setError(""); + } + onOpenChange(nextOpen); + }; + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + if (isSubmitting) return; + + const trimmedName = newName.trim(); + if (!trimmedName) { + setError("Group name is required."); + nameRef.current?.focus(); + return; + } + + onSave({ + name: trimmedName, + description: newDescription.trim() === "" ? null : newDescription.trim(), + }); + }; + + return ( + + { + if (isSubmitting) e.preventDefault(); + }} + onInteractOutside={(e) => { + if (isSubmitting) e.preventDefault(); + }} + > + + {group.name} + Edit the details for the {group.name} group. + + +
+ + +
+ + { + setNewName(e.target.value); + if (error) setError(""); + }} + aria-required="true" + aria-invalid={error ? true : undefined} + aria-describedby={error ? "groupName-error" : undefined} + className="border-2 border-black" + /> + {error && ( +

+ {error} +

+ )} +
+ +
+ +