@@ -1,4 +1,4 @@
|
||||
import { GalleryVerticalEnd, Home, Image, LocateOff, MapPinX, User } from "lucide-react";
|
||||
import { Album, GalleryHorizontal, GalleryVerticalEnd, Home, Image, LocateOff, MapPinX, User } from "lucide-react";
|
||||
|
||||
export const sidebarNavs = [
|
||||
{
|
||||
@@ -21,4 +21,9 @@ export const sidebarNavs = [
|
||||
link: "/assets/missing-locations",
|
||||
icon: <MapPinX className="h-4 w-4" />,
|
||||
},
|
||||
{
|
||||
title: "Albums",
|
||||
link: "/albums",
|
||||
icon: <GalleryHorizontal className="h-4 w-4" />,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
import { ASSET_THUMBNAIL_PATH } from '@/config/routes'
|
||||
import PageLayout from '@/components/layouts/PageLayout'
|
||||
import Header from '@/components/shared/Header'
|
||||
import Loader from '@/components/ui/loader'
|
||||
import { useConfig } from '@/contexts/ConfigContext'
|
||||
import { listAlbums } from '@/handlers/api/album.handler'
|
||||
import { IAlbum } from '@/types/album'
|
||||
import Image from 'next/image'
|
||||
import Link from 'next/link'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
|
||||
export default function AlbumListPage() {
|
||||
const { exImmichUrl } = useConfig()
|
||||
const [albums, setAlbums] = useState<IAlbum[]>([])
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [errorMessage, setErrorMessage] = useState('')
|
||||
|
||||
const fetchAlbums = async () => {
|
||||
setLoading(true)
|
||||
listAlbums()
|
||||
.then(setAlbums)
|
||||
.catch((error) => {
|
||||
setErrorMessage(error.message)
|
||||
})
|
||||
.finally(() => {
|
||||
setLoading(false)
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
fetchAlbums()
|
||||
}, [])
|
||||
|
||||
const renderContent = () => {
|
||||
|
||||
if (loading) {
|
||||
return <Loader />
|
||||
}
|
||||
else if (errorMessage) {
|
||||
return <div>{errorMessage}</div>
|
||||
}
|
||||
return (
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-4 p-4">
|
||||
{albums.map((album) => (
|
||||
<div key={album.id} className="border rounded-lg overflow-hidden shadow-lg">
|
||||
<Image
|
||||
src={ASSET_THUMBNAIL_PATH(album.albumThumbnailAssetId)} // Assuming this is a URL to the thumbnail
|
||||
alt={album.albumName}
|
||||
width={300}
|
||||
height={300}
|
||||
loading='lazy'
|
||||
className="w-full h-48 object-cover"
|
||||
/>
|
||||
<div className="p-4">
|
||||
<Link href={`${exImmichUrl}/albums/${album.id}`} target="_blank">
|
||||
<h2 className="text-md font-semibold truncate">{album.albumName}</h2>
|
||||
</Link>
|
||||
<p className="text-sm text-gray-700 dark:text-gray-500">{album.assetCount} assets</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<PageLayout className="!p-0 !mb-0">
|
||||
<Header
|
||||
leftComponent="Albums"
|
||||
/>
|
||||
{renderContent()}
|
||||
</PageLayout>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { pgTable, uuid, varchar, timestamp, boolean, text } from 'drizzle-orm/pg-core';
|
||||
|
||||
export const albums = pgTable('albums', {
|
||||
id: uuid('id').defaultRandom().primaryKey().notNull(),
|
||||
ownerId: uuid('ownerId').notNull(),
|
||||
albumName: varchar('albumName').notNull().default('Untitled Album'),
|
||||
createdAt: timestamp('createdAt', { withTimezone: true }).defaultNow().notNull(),
|
||||
albumThumbnailAssetId: uuid('albumThumbnailAssetId'),
|
||||
updatedAt: timestamp('updatedAt', { withTimezone: true }).defaultNow().notNull(),
|
||||
description: text('description').notNull().default(''),
|
||||
deletedAt: timestamp('deletedAt', { withTimezone: true }),
|
||||
isActivityEnabled: boolean('isActivityEnabled').notNull().default(true),
|
||||
order: varchar('order').notNull().default('desc'),
|
||||
});
|
||||
Reference in New Issue
Block a user