From b4fe518be4e59ed0c8f8369f6cf7ccaa28f45069 Mon Sep 17 00:00:00 2001 From: Isabel Keeper Date: Wed, 4 Mar 2026 16:24:43 -0500 Subject: [PATCH] Profile Image Component --- .../profile-components/image-scroll.tsx | 76 ++++++++++++++++ .../modals/image-manager.tsx | 88 +++++++++++++++++++ .../profile-components/profile-page.tsx | 7 +- web-app/components/ui/scroll-area.tsx | 58 ++++++++++++ web-app/mock/profiles.json | 5 ++ 5 files changed, 232 insertions(+), 2 deletions(-) create mode 100644 web-app/app/(profile)/profile/profile-components/image-scroll.tsx create mode 100644 web-app/app/(profile)/profile/profile-components/modals/image-manager.tsx create mode 100644 web-app/components/ui/scroll-area.tsx diff --git a/web-app/app/(profile)/profile/profile-components/image-scroll.tsx b/web-app/app/(profile)/profile/profile-components/image-scroll.tsx new file mode 100644 index 0000000..66f2a8d --- /dev/null +++ b/web-app/app/(profile)/profile/profile-components/image-scroll.tsx @@ -0,0 +1,76 @@ +"use client" + +import { useState } from "react" +import Image from "next/image" +import profiles from "mock/profiles.json" +import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area" +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog" +import { Plus } from "lucide-react" +import ImageManager from "./modals/image-manager"; + +type ImageItem = { + id: string + url: string +} + +export default function ProfileImageScroll({ userId }: { userId: string }) { + const user = profiles[0] + + const [images, setImages] = useState(() => + user.lifestyle_images?.map((url: string, index: number) => ({ + id: `${user.user_id}-${index}`, + url, + })) ?? [] + ) + + const [open, setOpen] = useState(false) + + return ( +
+ +
+ + + + + + + + + Manage Lifestyle Images + + + setOpen(false)} + /> + + + + {images.map((img) => ( +
+ Lifestyle image +
+ ))} +
+ + +
+
+ ) +} + diff --git a/web-app/app/(profile)/profile/profile-components/modals/image-manager.tsx b/web-app/app/(profile)/profile/profile-components/modals/image-manager.tsx new file mode 100644 index 0000000..1969c27 --- /dev/null +++ b/web-app/app/(profile)/profile/profile-components/modals/image-manager.tsx @@ -0,0 +1,88 @@ +"use client" + +import { useState } from "react" +import { Button } from "@/components/ui/button" + +type ImageItem = { + id: string + url: string +} + +type ImageManagerProps = { + images: ImageItem[] + setImages: React.Dispatch> + onClose: () => void +} + +export default function ImageManager({ images, setImages, onClose }: ImageManagerProps) { + const [localImages, setLocalImages] = useState(images) + + const handleAddField = () => { + setLocalImages((prev) => [ + ...prev, + { id: crypto.randomUUID(), url: "" }, + ]) + } + + const handleChange = (id: string, value: string) => { + setLocalImages((prev) => + prev.map((img) => + img.id === id ? { ...img, url: value } : img + ) + ) + } + + const handleRemove = (id: string) => { + setLocalImages((prev) => + prev.filter((img) => img.id !== id) + ) + } + + const handleSave = () => { + setImages(localImages.filter((img) => img.url.trim() !== "")) + onClose() + } + + const handleCancel = () => { + onClose() + } + + return ( +
+
+ {localImages.map((img) => ( +
+ + handleChange(img.id, e.target.value) + } + placeholder="Enter image URL (e.g. /demo/image1.jpg)" + className="flex-1 border rounded px-2 py-1" + /> + +
+ ))} +
+ + + +
+ + +
+
+ ) +} \ No newline at end of file diff --git a/web-app/app/(profile)/profile/profile-components/profile-page.tsx b/web-app/app/(profile)/profile/profile-components/profile-page.tsx index 09fd66b..84bb8c8 100644 --- a/web-app/app/(profile)/profile/profile-components/profile-page.tsx +++ b/web-app/app/(profile)/profile/profile-components/profile-page.tsx @@ -2,6 +2,7 @@ import { Card } from "@/components/ui/card" import EditName from "./modals/edit-name" import profiles from "mock/profiles.json" import SelectHobbies from "./modals/hobby-select"; +import ProfileImageScroll from "./image-scroll"; export default function ProfilePage() { const user = profiles[0]; @@ -38,8 +39,10 @@ export default function ProfilePage() { - - + +

Images

+ +
diff --git a/web-app/components/ui/scroll-area.tsx b/web-app/components/ui/scroll-area.tsx new file mode 100644 index 0000000..73c4eb1 --- /dev/null +++ b/web-app/components/ui/scroll-area.tsx @@ -0,0 +1,58 @@ +"use client" + +import * as React from "react" +import { ScrollArea as ScrollAreaPrimitive } from "radix-ui" + +import { cn } from "@/lib/utils" + +function ScrollArea({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + {children} + + + + + ) +} + +function ScrollBar({ + className, + orientation = "vertical", + ...props +}: React.ComponentProps) { + return ( + + + + ) +} + +export { ScrollArea, ScrollBar } diff --git a/web-app/mock/profiles.json b/web-app/mock/profiles.json index 60edf16..55ec68e 100644 --- a/web-app/mock/profiles.json +++ b/web-app/mock/profiles.json @@ -16,6 +16,11 @@ ["smoker", "no"], ["pets", "yes"], ["sleep_schedule", "early"] + ], + "lifestyle_images": [ + "/demo/selfie.png", + "/demo/room1.png", + "/demo/room2.png" ] }, {