Skip to content

Commit

Permalink
Merge pull request #136 from varun-raj/pre-release
Browse files Browse the repository at this point in the history
Feb Release
  • Loading branch information
varun-raj authored Feb 6, 2025
2 parents c5ffba6 + d7d6458 commit 4f94bcf
Show file tree
Hide file tree
Showing 27 changed files with 498 additions and 222 deletions.
2 changes: 1 addition & 1 deletion src/components/albums/list/AlbumThumbnail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export default function AlbumThumbnail({ album, onSelect, selected }: IAlbumThum
}}
/>
<div className="absolute bottom-0 w-full bg-gray-800/70 text-white text-center text-xs font-bold py-1 group-hover:hidden">
{formatDate(album.firstPhotoDate.toString(), 'MMM d, yyyy')} - {formatDate(album.lastPhotoDate.toString(), 'MMM d, yyyy')}
{album.firstPhotoDate ? formatDate(album.firstPhotoDate?.toString(), 'MMM d, yyyy') : ''} - {album.lastPhotoDate ? formatDate(album.lastPhotoDate?.toString(), 'MMM d, yyyy') : ''}
</div>
<Checkbox
defaultChecked={isSelected}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { ArrowDown, ArrowUp, ArrowUpDownIcon, SortAsc, SortDesc } from "lucide-r

export default function PotentialAlbumsDates() {
const router = useRouter();
const { updateContext } = usePotentialAlbumContext();
const { updateContext, minAssets } = usePotentialAlbumContext();
const [dateRecords, setDateRecords] = React.useState<
IPotentialAlbumsDatesResponse[]
>([]);
Expand All @@ -26,6 +26,7 @@ export default function PotentialAlbumsDates() {
return listPotentialAlbumsDates({
sortBy: filters.sortBy,
sortOrder: filters.sortOrder,
minAssets,
})
.then(setDateRecords)
.catch(setErrorMessage)
Expand All @@ -43,7 +44,7 @@ export default function PotentialAlbumsDates() {

useEffect(() => {
fetchData();
}, [filters]);
}, [filters, minAssets]);

return (
<div className="min-w-[200px] py-4 max-h-[calc(100vh-60px)] min-h-[calc(100vh-60px)] border-r border-gray-200 dark:border-zinc-800 flex flex-col gap-2 px-1">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,15 @@ export default function MissingLocationAssets({ groupBy }: IProps) {
[images]
);

const handleClick = (idx: number) => setIndex(idx);
const handleClick = (idx: number, asset: IAsset, event: MouseEvent<HTMLElement>) => {
if (selectedIds.length > 0) {
handleSelect(idx, asset, event);
}
else
{
setIndex(idx);
}
};

const handleSelect = (_idx: number, asset: IAsset, event: MouseEvent<HTMLElement>) => {
event.stopPropagation();
Expand Down
17 changes: 15 additions & 2 deletions src/components/assets/missing-location/MissingLocationDateItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,26 @@ import { useMissingLocationContext } from "@/contexts/MissingLocationContext";
import { IMissingLocationDatesResponse } from "@/handlers/api/asset.handler";
import { parseDate, formatDate } from "@/helpers/date.helper";
import { cn } from "@/lib/utils";
import React, { useMemo } from "react";
import React, { useEffect, useMemo, useRef } from "react";

interface IProps {
record: IMissingLocationDatesResponse;
onSelect: (date: string) => void;
groupBy: "date" | "album";
}

export default function MissingLocationDateItem({ record, onSelect, groupBy }: IProps) {
// Effect to handle scrolling after rendering
useEffect(() => {
if (startDate === record.label) {
itemsRef.current?.scrollIntoView({
behavior: "smooth", // Smooth scrolling
block: "center", // Center the item in the view
});
}
}, []);

const itemsRef = useRef<HTMLDivElement | null>(null);
const { startDate } = useMissingLocationContext()

const dateLabel = useMemo(() => {
Expand All @@ -34,9 +46,10 @@ export default function MissingLocationDateItem({ record, onSelect, groupBy }: I
cn("flex gap-1 flex-col p-1 rounded-lg hover:dark:bg-zinc-800 border border-transparent hover:bg-zinc-100",
startDate === record.label ? "bg-zinc-100 dark:bg-zinc-800 border-gray-300 dark:border-zinc-700" : "")
}
ref={itemsRef}
>
<p className="text-sm truncate">{dateLabel}</p>
<p className="text-xs text-foreground/50">{record.asset_count} Orphan Assets</p>
<p className="text-xs text-foreground/50">{record.asset_count} Assets</p>
</div>
);
}
11 changes: 4 additions & 7 deletions src/components/assets/missing-location/MissingLocationDates.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,21 @@ interface IMissingLocationDatesProps {

}
export default function MissingLocationDates({ groupBy }: IMissingLocationDatesProps) {
const { updateContext } = useMissingLocationContext();
const { dates, updateContext } = useMissingLocationContext();
const router = useRouter();
const [dateRecords, setDateRecords] = React.useState<
IMissingLocationDatesResponse[]
>([]);
const [filters, setFilters] = useState<{ sortBy: string, sortOrder: string }>({ sortBy: "date", sortOrder: "desc" });
const [loading, setLoading] = useState(false);

const [errorMessage, setErrorMessage] = useState<string | null>(null);

const fetchData = async () => {
const func = groupBy === "album" ? listMissingLocationAlbums : listMissingLocationDates
setDateRecords([])
updateContext({ dates: [] })
return func({
sortBy: filters.sortBy,
sortOrder: filters.sortOrder,
})
.then(setDateRecords)
.then((r) => updateContext({ dates: r }))
.catch(setErrorMessage)
.finally(() => setLoading(false));
};
Expand Down Expand Up @@ -96,7 +93,7 @@ export default function MissingLocationDates({ groupBy }: IMissingLocationDatesP
</div>
</div>
<div className="overflow-y-auto flex flex-col gap-2">
{dateRecords.map((record) => (
{dates.map((record) => (
<MissingLocationDateItem
key={record.value}
record={record}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,19 @@ export default function TagMissingLocationDialog({
Tagging a location will add the location to the selected assets.
</DialogDescription>
</DialogHeader>
<Tabs defaultValue="search" className="border rounded-lg">
<Tabs defaultValue="searchOsm" className="border rounded-lg">
<TabsList className="flex justify-between">
<TabsTrigger value="search">Immich Search</TabsTrigger>
<TabsTrigger value="searchOsm">OSM Search</TabsTrigger>
<TabsTrigger value="latlong">Lat &amp; Long</TabsTrigger>
<TabsTrigger value="maps">Map</TabsTrigger>
<TabsTrigger value="searchOsm" className="w-full">Open Street Map</TabsTrigger>
<TabsTrigger value="search" className="w-full">Immich Geo</TabsTrigger>
<TabsTrigger value="latlong" className="w-full">Lat &amp; Long</TabsTrigger>
<TabsTrigger value="maps" className="w-full">Map</TabsTrigger>
</TabsList>
<TabsContent value="search">
<TagMissingLocationSearchAndAdd onSubmit={onSubmit} onOpenChange={setOpen} />
</TabsContent>
<TabsContent value="searchOsm">
<TagMissingLocationOSMSearchAndAdd onSubmit={onSubmit} onOpenChange={setOpen} location={mapPosition} onLocationChange={setMapPosition} />
</TabsContent>
<TabsContent value="search">
<TagMissingLocationSearchAndAdd onSubmit={onSubmit} onOpenChange={setOpen} />
</TabsContent>
<TabsContent value="latlong">
<TagMissingLocationSearchLatLong onSubmit={onSubmit} onOpenChange={setOpen} location={mapPosition} onLocationChange={setMapPosition} />
</TabsContent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ export default function TagMissingLocationOSMSearchAndAdd(
setSelectedPlace(null);
} else {
setSelectedPlace(place);
debugger;
onLocationChange(place);
}
};
Expand Down Expand Up @@ -132,15 +131,12 @@ export default function TagMissingLocationOSMSearchAndAdd(

return (
<div className="flex flex-col gap-4 py-4 px-2">
<div className="flex flex-col gap-2">
<Label>Search Location</Label>
<Input
placeholder="Search location"
onChange={(e) => {
handleSearch(e.target.value);
}}
/>
</div>
<div>
{loading && <Loader />}
{!loading && searchedPlaces && searchedPlaces.length === 0 && (
Expand All @@ -153,21 +149,21 @@ export default function TagMissingLocationOSMSearchAndAdd(
key={place.name}
onClick={() => handleSelect(place)}
className={cn(
"hover:bg-gray-300 flex justify-between items-center px-2 py-1 rounded-lg cursor-pointer",
"hover:bg-gray-300 dark:hover:bg-gray-700 flex justify-between items-center px-2 py-1 rounded-lg cursor-pointer",
{
"bg-gray-300":
"bg-gray-300 dark:bg-gray-700":
selectedPlace && selectedPlace.name === place.name,
}
)}
>
<div>
<p>{place.name}</p>
<span className="text-xs text-gray-600">
<p className="text-sm">{place.name}</p>
<span className="text-xs text-gray-600 dark:text-gray-400">
{place.latitude}, {place.longitude}
</span>
</div>
{selectedPlace && selectedPlace.name === place.name && (
<Check className="text-green-500" />
<Check className="text-green-500 dark:text-green-400" />
)}
</div>
))}
Expand All @@ -176,11 +172,11 @@ export default function TagMissingLocationOSMSearchAndAdd(
</div>
<div className="self-end">
<Button
variant="outline"
variant="default"
onClick={handleSubmit}
disabled={!selectedPlace || submitting}
>
Add New Location
Tag Location
</Button>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ export default function TagMissingLocationSearchAndAdd(
return (
<div className="flex flex-col gap-4 py-4 px-2">
<div className="flex flex-col gap-2">
<Label>Search Location</Label>
<Input
placeholder="Search location"
onChange={(e) => {
Expand All @@ -116,21 +115,21 @@ export default function TagMissingLocationSearchAndAdd(
key={place.name}
onClick={() => handleSelect(place)}
className={cn(
"hover:bg-zinc-900 flex justify-between items-center px-2 py-1 rounded-lg cursor-pointer",
"hover:bg-zinc-200 dark:hover:bg-zinc-800 flex justify-between items-center px-2 py-1 rounded-lg cursor-pointer",
{
"bg-zinc-900":
"bg-zinc-900 dark:bg-zinc-200":
selectedPlace && selectedPlace.name === place.name,
}
)}
>
<div>
<p>{place.name}</p>
<span className="text-xs text-gray-600">
<span className="text-xs text-gray-600 dark:text-gray-200">
{place.latitude}, {place.longitude}
</span>
</div>
{selectedPlace && selectedPlace.name === place.name && (
<Check className="text-green-500" />
<Check className="text-green-500 dark:text-green-400" />
)}
</div>
))}
Expand All @@ -139,11 +138,11 @@ export default function TagMissingLocationSearchAndAdd(
</div>
<div className="self-end">
<Button
variant="outline"
variant="default"
onClick={handleSubmit}
disabled={!selectedPlace || submitting}
>
Add New Location
Tag Location
</Button>
</div>
</div>
Expand Down
24 changes: 21 additions & 3 deletions src/components/people/PeopleFilters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,27 @@ import {
import { Input } from "../ui/input";
import { IPersonListFilters } from "@/handlers/api/people.handler";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
import { removeNullOrUndefinedProperties } from "@/helpers/data.helper";
import { ParsedUrlQueryInput } from "querystring";

export function PeopleFilters() {
const router = useRouter();
const { updateContext, page, maximumAssetCount, type = "all", query ="" } = usePeopleFilterContext();
const { updateContext, page, maximumAssetCount, type = "all", query = "", visibility = "all" } = usePeopleFilterContext();

const handleChange = (data: Partial<IPersonListFilters>) => {
updateContext(data);
router.push({
pathname: router.pathname,
query: {
query: {
...router.query,
...data,
...data,
page: data.page || undefined,
type: data.type || undefined,
visibility: data.visibility || undefined,
query: data.query || undefined,
maximumAssetCount: data.maximumAssetCount || undefined,
sort: data.sort || undefined,
sortOrder: data.sortOrder || undefined,
},
});
}
Expand Down Expand Up @@ -73,6 +80,17 @@ export function PeopleFilters() {
</SelectContent>
</Select>

<Select value={visibility} onValueChange={(value) => handleChange({ visibility: value as "all" | "visible" | "hidden" })}>
<SelectTrigger>
<SelectValue placeholder="Visibility" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">All</SelectItem>
<SelectItem value="visible">Visible</SelectItem>
<SelectItem value="hidden">Hidden</SelectItem>
</SelectContent>
</Select>

<Button
disabled={prevPage < 1}
onClick={() => handleChange({ page: prevPage })}
Expand Down
2 changes: 1 addition & 1 deletion src/components/people/PersonItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ export default function PersonItem({ person, onRemove }: IProps) {
<Button variant="outline" className="!py-0.5 !px-2 text-xs h-7" onClick={() => {
handleHide(!formData.isHidden);
}}>
Hide
{formData.isHidden ? "Show" : "Hide"}
</Button>
<ShareAssetsTrigger filters={{ personIds: [person.id] }} buttonProps={{ variant: "outline", className: "!py-0.5 !px-2 text-xs h-7" }} />
</div>
Expand Down
63 changes: 63 additions & 0 deletions src/components/shared/AlbumDropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { listAlbums } from '@/handlers/api/album.handler';
import { IAlbum } from '@/types/album';
import React, { useEffect, useState } from 'react'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../ui/select';
import { X } from 'lucide-react';

interface IAlbumDropdownProps {
albumIds?: string[];
onChange: (albumIds: string[]) => void;
}
export default function AlbumDropdown({ albumIds, onChange }: IAlbumDropdownProps) {
const [albums, setAlbums] = useState<IAlbum[]>([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [selectedAlbumIds, setSelectedAlbumIds] = useState(albumIds);

const fetchAlbums = async () => {
setLoading(true);
return listAlbums({
sortBy: "createdAt",
sortOrder: "desc",
}).then((albums) => setAlbums(albums)).catch((error) => setError(error)).finally(() => setLoading(false)) ;
}

useEffect(() => {
fetchAlbums();
}, []);


useEffect(() => {
if (albumIds) {
setSelectedAlbumIds(albumIds);
} else {
setSelectedAlbumIds([]);
}
}, [albumIds]);

return (
<div>
<Select
onValueChange={(value) => {
if (value) {
setSelectedAlbumIds([value])
onChange([value])
} else {
setSelectedAlbumIds([])
onChange([])
}
}}
value={selectedAlbumIds?.[0] ?? ""}
>
<SelectTrigger className='!p-2'>
<SelectValue placeholder={'Select album'} />
</SelectTrigger>
<SelectContent>
{albums.map((album) => (
<SelectItem key={album.id} value={album.id}>{album.albumName}</SelectItem>
))}
</SelectContent>
</Select>
</div>
)
}
Loading

0 comments on commit 4f94bcf

Please sign in to comment.