"use client"; import type { PhotoData } from "@/server/api/routers/photos/list"; import { api } from "@/trpc/react"; import Image from "next/image"; import type React from "react"; import { useState } from "react"; import ImageSvg from "./file-svg"; import DirSvg from "./dir-svg"; import { Controller, useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import z from "zod"; import Tiptap from "./photo-editor"; const FormSchema = z.object({ title: z .string() .min(3, "Title should be over 3 characters") .max(128, "Title cannot be over 128 characters"), description: z.object({ type: z.string(), content: z.array(z.unknown()), }), }); type IFormInput = z.infer; interface DirectoryTree { [key: string]: DirectoryTree; } function buildDirectoryTree(filePaths: string[]): DirectoryTree { const root: DirectoryTree = {}; filePaths.forEach((path) => { const parts = path.split("/").filter((p) => p.length > 0); let current = root; // Traverse or create nodes for each part of the path for (let i = 0; i < parts.length; i++) { const part = parts[i]; if (part) { if (!current[part]) { current[part] = {}; } current = current[part]; } } }); return root; } type Item = { type: "directory" | "file"; name: string; fullPath: string; children?: Item[]; }; function renderTree(node: DirectoryTree, pathSoFar = ""): Item[] { const entries = Object.entries(node); const items: Item[] = []; for (const [name, children] of entries) { const fullPath = pathSoFar ? `${pathSoFar}/${name}` : name; const isLeaf = Object.keys(children).length === 0; if (isLeaf) { // It's a file items.push({ type: "file", name, fullPath }); } else { // It's a directory items.push({ type: "directory", name, fullPath, children: renderTree(children, fullPath), }); } } return items; } function RenderLeaf(leaf: Item[], selectImageTab: (path: string) => void) { return leaf.map((leaf) => { if (leaf.children?.length) { return (
  • {leaf.name}
      {RenderLeaf(leaf.children, selectImageTab)}
  • ); } return (
  • ); }); } export function PhotoTab(): React.JSX.Element { const [selectedImage, setSelectedImage] = useState(); const query = api.photos.list.useQuery(undefined, { refetchOnWindowFocus: false, }); const { register, handleSubmit, control, formState: { errors }, } = useForm({ resolver: zodResolver(FormSchema), mode: "onSubmit", }); if (query.isLoading) { return

    Loading

    ; } if (query.error) { return

    {query.error.message}

    ; } const images = query.data?.data; if (!images || images?.length === 0) { return

    No Images

    ; } const selectImageTab = (path: string) => { const img = images.find( (img) => img.src === `https://fly.storage.tigris.dev/joemonk-photos/${path}`, ); setSelectedImage(img); }; const tree = buildDirectoryTree( images.map((img) => img.src.substring( "https://fly.storage.tigris.dev/joemonk-photos/".length, ), ), ); const renderedTree = renderTree(tree); const onSubmit = (data: IFormInput) => { console.log(data); }; return (
      {RenderLeaf(renderedTree, selectImageTab)}
    {selectedImage?.src ? (
    {selectedImage?.title
    {[ { title: "F-Stop", value: selectedImage.exif.fNumber?.toString(), }, { title: "ISO", value: selectedImage.exif.isoSpeedRatings?.toString(), }, { title: "Exposure", value: selectedImage.exif.exposureBiasValue?.toString(), }, ].map((setting) => { return (
    {setting.title} {setting.value}
    ); })}
    {[ { title: "Taken", value: selectedImage.exif.takenAt?.toLocaleDateString(), }, { title: "Lens", value: selectedImage.exif.LensModel, }, { title: "Camera", value: selectedImage.camera, }, ].map((setting) => { return (
    {setting.title} {setting.value}
    ); })}
    {[ { title: "Height", value: selectedImage.height.toString(), }, { title: "Width", value: selectedImage.width.toString(), }, ].map((setting) => { return (
    {setting.title} {setting.value}
    ); })}
    Description ( )} />
    ) : null}
    ); }