diff --git a/src/components/albums/info/AlbumImages.tsx b/src/components/albums/info/AlbumImages.tsx index e789a83..0736e9f 100644 --- a/src/components/albums/info/AlbumImages.tsx +++ b/src/components/albums/info/AlbumImages.tsx @@ -1,7 +1,7 @@ import "yet-another-react-lightbox/styles.css"; import { listAlbumAssets } from "@/handlers/api/album.handler"; import { useConfig } from "@/contexts/ConfigContext"; -import { IAlbum } from "@/types/album"; +import { IAlbum, IAlbumPerson } from "@/types/album"; import { IAsset } from "@/types/asset"; import React, { useEffect, useMemo, useRef, useState, MouseEvent } from "react"; import { Hourglass } from "lucide-react"; @@ -12,9 +12,12 @@ import Lightbox from "yet-another-react-lightbox"; import Captions from "yet-another-react-lightbox/plugins/captions"; import LazyGridImage from "@/components/ui/lazy-grid-image"; import { usePhotoSelectionContext } from "@/contexts/PhotoSelectionContext"; +import { PERSON_THUBNAIL_PATH } from "@/config/routes"; +import Image from "next/image"; interface AlbumImagesProps { album: IAlbum; + selectedPerson: IAlbumPerson | null; } interface IAssetFilter { @@ -22,7 +25,7 @@ interface IAssetFilter { page: number; } -export default function AlbumImages({ album }: AlbumImagesProps) { +export default function AlbumImages({ album, selectedPerson }: AlbumImagesProps) { const { exImmichUrl } = useConfig(); const router = useRouter(); const { faceId } = router.query as { faceId: string }; @@ -158,6 +161,7 @@ export default function AlbumImages({ album }: AlbumImagesProps) { return ( <> + (({ album const [selectionMode, setSelectionMode] = useState(false) const [selectedPeople, setSelectedPeople] = useState([]) const [searchQuery, setSearchQuery] = useState("") - + const selectedPerson = useMemo(() => { return people.find((person) => query.faceId === person.id) }, [people, query.faceId]) @@ -108,7 +111,7 @@ const AlbumPeople = React.forwardRef(({ album } }) } - + useEffect(() => { fetchPeople() @@ -157,7 +160,7 @@ const AlbumPeople = React.forwardRef(({ album @@ -172,12 +175,29 @@ const AlbumPeople = React.forwardRef(({ album return (
- setSearchQuery(e.target.value)} - /> +
+ setSearchQuery(e.target.value)} + /> + {!readOnly && !selectedPerson && ( + + )} +
{selectedPerson && (
@@ -189,6 +209,7 @@ const AlbumPeople = React.forwardRef(({ album className="rounded-full" /> + {selectedPerson.name || "No Name"} @@ -224,45 +245,51 @@ const AlbumPeople = React.forwardRef(({ album )}
- -
-

Known People

- {!readOnly && ( - <> - {!selectedPerson && ( - - )} - {selectedPeople.length > 0 && ( -
- + + + +
+

Known ({knownPeople.length})

- )} - - )} -
-
- {knownPeople.map(renderPerson)} -
- {unknownPeople.length > 0 && ( -
-
-

Unknown People

- + + +
+ {knownPeople.map(renderPerson)} +
+
+ + + {unknownPeople.length > 0 && ( + + +
+

Unknown ({unknownPeople.length})

+ { + handleUnknownPeopleCheck(checked) + }} + onClick={(e) => e.stopPropagation()} + /> +
+
+ +
+ {unknownPeople.map(renderPerson)} +
+
+
+ )} + + + {selectedPeople.length > 0 && ( +
+
- {unknownPeople.map(renderPerson)} -
- )} + )}
) diff --git a/src/components/albums/info/AlbumPersonNameBar.tsx b/src/components/albums/info/AlbumPersonNameBar.tsx index 5852ea1..900f2ef 100644 --- a/src/components/albums/info/AlbumPersonNameBar.tsx +++ b/src/components/albums/info/AlbumPersonNameBar.tsx @@ -1,13 +1,12 @@ import FloatingBar from '@/components/shared/FloatingBar' import { AlertDialog, IAlertDialogActions } from '@/components/ui/alert-dialog' import { Autocomplete, AutocompleteOption } from '@/components/ui/autocomplete' -import { Button } from '@/components/ui/button' -import { Input } from '@/components/ui/input' import { useToast } from '@/components/ui/use-toast' +import { PERSON_THUBNAIL_PATH } from '@/config/routes' import { mergePerson, searchPeople, updatePerson } from '@/handlers/api/people.handler' import { IAlbumPerson } from '@/types/album' +import Image from 'next/image' import { useRef, useState } from 'react' -import { Toaster } from 'react-hot-toast' interface AlbumPersonNameBarProps { selectedPerson: IAlbumPerson | null diff --git a/src/components/shared/FloatingBar.tsx b/src/components/shared/FloatingBar.tsx index 7793795..701d509 100644 --- a/src/components/shared/FloatingBar.tsx +++ b/src/components/shared/FloatingBar.tsx @@ -6,7 +6,7 @@ interface FloatingBarProps { export default function FloatingBar({ children }: FloatingBarProps) { return ( -
+
{children}
) diff --git a/src/pages/albums/[albumId].tsx b/src/pages/albums/[albumId].tsx index 7012e8c..2cf9e87 100644 --- a/src/pages/albums/[albumId].tsx +++ b/src/pages/albums/[albumId].tsx @@ -68,8 +68,8 @@ export default function AlbumListPage() { useEffect(() => { fetchAlbumInfo() - }, []) + }, []) // Update context albumId when router albumId changes useEffect(() => { contextState.updateContext({ @@ -137,7 +137,7 @@ export default function AlbumListPage() { {albumInfo && ( <> - + )}
diff --git a/src/pages/api/albums/[id]/assets.ts b/src/pages/api/albums/[id]/assets.ts index 78b68bb..78e5b2e 100644 --- a/src/pages/api/albums/[id]/assets.ts +++ b/src/pages/api/albums/[id]/assets.ts @@ -3,7 +3,7 @@ import { NextApiRequest } from "next"; import { db } from "@/config/db"; import { getCurrentUser } from "@/handlers/serverUtils/user.utils"; import { NextApiResponse } from "next"; -import { and, eq, isNotNull } from "drizzle-orm"; +import { and, desc, eq, isNotNull } from "drizzle-orm"; import { assets } from "@/schema/assets.schema"; import { albumsAssetsAssets } from "@/schema/albumAssetsAssets.schema"; import { assetFaces, exif, person } from "@/schema"; @@ -56,6 +56,7 @@ export default async function handler( eq(assets.status, "active"), faceId ? eq(assetFaces.personId, faceId) : undefined, )) + .orderBy(desc(assets.id), desc(assets.localDateTime)) .limit(100) .offset(100 * (page - 1)); @@ -71,6 +72,8 @@ export default async function handler( orientation: asset?.orientation, downloadUrl: asset?.id ? ASSET_VIDEO_PATH(asset.id) : null, }; + }).sort((b, a) => { + return new Date(b.localDateTime || 0).getTime() - new Date(a.localDateTime || 0).getTime(); }); res.status(200).json(cleanedAssets); } \ No newline at end of file