feat: integrate display preferences for pagination and compact view in series grid

This commit is contained in:
Julien Froidefond
2025-03-30 07:37:39 +02:00
parent fcd084863a
commit a2c7519ac5
4 changed files with 104 additions and 13 deletions

View File

@@ -9,6 +9,7 @@ import { cn } from "@/lib/utils";
import type { KomgaSeries } from "@/types/komga"; import type { KomgaSeries } from "@/types/komga";
import { SearchInput } from "./SearchInput"; import { SearchInput } from "./SearchInput";
import { useTranslate } from "@/hooks/useTranslate"; import { useTranslate } from "@/hooks/useTranslate";
import { useDisplayPreferences } from "@/hooks/useDisplayPreferences";
import { import {
Select, Select,
SelectContent, SelectContent,
@@ -22,7 +23,6 @@ interface PaginatedSeriesGridProps {
currentPage: number; currentPage: number;
totalPages: number; totalPages: number;
totalElements: number; totalElements: number;
pageSize: number;
defaultShowOnlyUnread: boolean; defaultShowOnlyUnread: boolean;
showOnlyUnread: boolean; showOnlyUnread: boolean;
} }
@@ -32,7 +32,6 @@ export function PaginatedSeriesGrid({
currentPage, currentPage,
totalPages, totalPages,
totalElements, totalElements,
pageSize,
defaultShowOnlyUnread, defaultShowOnlyUnread,
showOnlyUnread: initialShowOnlyUnread, showOnlyUnread: initialShowOnlyUnread,
}: PaginatedSeriesGridProps) { }: PaginatedSeriesGridProps) {
@@ -41,7 +40,8 @@ export function PaginatedSeriesGrid({
const searchParams = useSearchParams(); const searchParams = useSearchParams();
const [isChangingPage, setIsChangingPage] = useState(false); const [isChangingPage, setIsChangingPage] = useState(false);
const [showOnlyUnread, setShowOnlyUnread] = useState(initialShowOnlyUnread); const [showOnlyUnread, setShowOnlyUnread] = useState(initialShowOnlyUnread);
const [isCompact, setIsCompact] = useState(searchParams.get("compact") === "true"); const { isCompact, itemsPerPage, handleCompactToggle, handlePageSizeChange } =
useDisplayPreferences();
const { t } = useTranslate(); const { t } = useTranslate();
const updateUrlParams = async (updates: Record<string, string | null>) => { const updateUrlParams = async (updates: Record<string, string | null>) => {
@@ -78,7 +78,7 @@ export function PaginatedSeriesGrid({
}, [defaultShowOnlyUnread, pathname, router, searchParams]); }, [defaultShowOnlyUnread, pathname, router, searchParams]);
const handlePageChange = async (page: number) => { const handlePageChange = async (page: number) => {
await updateUrlParams({ page: page.toString(), compact: isCompact.toString() }); await updateUrlParams({ page: page.toString() });
}; };
const handleUnreadFilter = async () => { const handleUnreadFilter = async () => {
@@ -87,30 +87,30 @@ export function PaginatedSeriesGrid({
await updateUrlParams({ await updateUrlParams({
page: "1", page: "1",
unread: newUnreadState ? "true" : "false", unread: newUnreadState ? "true" : "false",
compact: isCompact.toString(),
}); });
}; };
const handleCompactToggle = async () => { const handleCompactToggleClick = async () => {
const newCompactState = !isCompact; const newCompactState = !isCompact;
setIsCompact(newCompactState); await handleCompactToggle(newCompactState);
await updateUrlParams({ await updateUrlParams({
page: "1", page: "1",
compact: newCompactState.toString(), compact: newCompactState.toString(),
}); });
}; };
const handlePageSizeChange = async (value: string) => { const handlePageSizeChangeClick = async (value: string) => {
const size = parseInt(value);
await handlePageSizeChange(size);
await updateUrlParams({ await updateUrlParams({
page: "1", page: "1",
size: value, size: value,
compact: isCompact.toString(),
}); });
}; };
// Calculate start and end indices for display // Calculate start and end indices for display
const startIndex = (currentPage - 1) * pageSize + 1; const startIndex = (currentPage - 1) * itemsPerPage + 1;
const endIndex = Math.min(currentPage * pageSize, totalElements); const endIndex = Math.min(currentPage * itemsPerPage, totalElements);
const getShowingText = () => { const getShowingText = () => {
if (!totalElements) return t("series.empty"); if (!totalElements) return t("series.empty");
@@ -130,7 +130,7 @@ export function PaginatedSeriesGrid({
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<p className="text-sm text-muted-foreground">{getShowingText()}</p> <p className="text-sm text-muted-foreground">{getShowingText()}</p>
<Select value={pageSize.toString()} onValueChange={handlePageSizeChange}> <Select value={itemsPerPage.toString()} onValueChange={handlePageSizeChangeClick}>
<SelectTrigger className="w-[80px]"> <SelectTrigger className="w-[80px]">
<LayoutList className="h-4 w-4 mr-2" /> <LayoutList className="h-4 w-4 mr-2" />
<SelectValue /> <SelectValue />
@@ -142,7 +142,7 @@ export function PaginatedSeriesGrid({
</SelectContent> </SelectContent>
</Select> </Select>
<button <button
onClick={handleCompactToggle} onClick={handleCompactToggleClick}
className="inline-flex items-center gap-2 px-2 py-1.5 text-sm font-medium rounded-lg hover:bg-accent hover:text-accent-foreground whitespace-nowrap" className="inline-flex items-center gap-2 px-2 py-1.5 text-sm font-medium rounded-lg hover:bg-accent hover:text-accent-foreground whitespace-nowrap"
> >
{isCompact ? ( {isCompact ? (

View File

@@ -0,0 +1,60 @@
import { usePreferences } from "@/contexts/PreferencesContext";
import { useToast } from "@/components/ui/use-toast";
import { useTranslate } from "@/hooks/useTranslate";
export function useDisplayPreferences() {
const { preferences, updatePreferences } = usePreferences();
const { toast } = useToast();
const { t } = useTranslate();
const handleCompactToggle = async (checked: boolean) => {
try {
await updatePreferences({
displayMode: {
...preferences.displayMode,
compact: checked,
},
});
toast({
title: t("settings.title"),
description: t("settings.komga.messages.configSaved"),
});
} catch (error) {
console.error("Erreur lors de la mise à jour du mode compact:", error);
toast({
variant: "destructive",
title: t("settings.error.title"),
description: t("settings.error.message"),
});
}
};
const handlePageSizeChange = async (size: number) => {
try {
await updatePreferences({
displayMode: {
...preferences.displayMode,
itemsPerPage: size,
},
});
toast({
title: t("settings.title"),
description: t("settings.komga.messages.configSaved"),
});
} catch (error) {
console.error("Erreur lors de la mise à jour de la taille de page:", error);
toast({
variant: "destructive",
title: t("settings.error.title"),
description: t("settings.error.message"),
});
}
};
return {
isCompact: preferences.displayMode.compact,
itemsPerPage: preferences.displayMode.itemsPerPage,
handleCompactToggle,
handlePageSizeChange,
};
}

View File

@@ -26,6 +26,17 @@ const preferencesSchema = new mongoose.Schema(
default: false, default: false,
required: false, required: false,
}, },
displayMode: {
compact: {
type: Boolean,
default: false,
},
itemsPerPage: {
type: Number,
default: 20,
enum: [20, 50, 100],
},
},
}, },
{ {
timestamps: true, timestamps: true,
@@ -35,6 +46,8 @@ const preferencesSchema = new mongoose.Schema(
// Force la conversion en booléen // Force la conversion en booléen
ret.showOnlyUnread = Boolean(ret.showOnlyUnread); ret.showOnlyUnread = Boolean(ret.showOnlyUnread);
ret.debug = Boolean(ret.debug); ret.debug = Boolean(ret.debug);
ret.displayMode = ret.displayMode || { compact: false, itemsPerPage: 20 };
ret.displayMode.compact = Boolean(ret.displayMode.compact);
return ret; return ret;
}, },
}, },
@@ -49,8 +62,12 @@ preferencesSchema.pre("save", function (next) {
if (this.debug === undefined) { if (this.debug === undefined) {
this.debug = false; this.debug = false;
} }
if (!this.displayMode) {
this.displayMode = { compact: false, itemsPerPage: 20 };
}
this.showOnlyUnread = Boolean(this.showOnlyUnread); this.showOnlyUnread = Boolean(this.showOnlyUnread);
this.debug = Boolean(this.debug); this.debug = Boolean(this.debug);
this.displayMode.compact = Boolean(this.displayMode.compact);
next(); next();
}); });
@@ -63,6 +80,12 @@ preferencesSchema.pre("findOneAndUpdate", function (next) {
if ("debug" in update.$set) { if ("debug" in update.$set) {
update.$set.debug = Boolean(update.$set.debug); update.$set.debug = Boolean(update.$set.debug);
} }
if ("displayMode" in update.$set) {
update.$set.displayMode = {
compact: Boolean(update.$set.displayMode?.compact),
itemsPerPage: update.$set.displayMode?.itemsPerPage || 20,
};
}
} }
next(); next();
}); });

View File

@@ -3,6 +3,10 @@ export interface UserPreferences {
cacheMode: "memory" | "file"; cacheMode: "memory" | "file";
showOnlyUnread: boolean; showOnlyUnread: boolean;
debug: boolean; debug: boolean;
displayMode: {
compact: boolean;
itemsPerPage: number;
};
} }
export const defaultPreferences: UserPreferences = { export const defaultPreferences: UserPreferences = {
@@ -10,4 +14,8 @@ export const defaultPreferences: UserPreferences = {
cacheMode: "memory", cacheMode: "memory",
showOnlyUnread: false, showOnlyUnread: false,
debug: false, debug: false,
displayMode: {
compact: false,
itemsPerPage: 20,
},
} as const; } as const;