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 { SearchInput } from "./SearchInput";
import { useTranslate } from "@/hooks/useTranslate";
import { useDisplayPreferences } from "@/hooks/useDisplayPreferences";
import {
Select,
SelectContent,
@@ -22,7 +23,6 @@ interface PaginatedSeriesGridProps {
currentPage: number;
totalPages: number;
totalElements: number;
pageSize: number;
defaultShowOnlyUnread: boolean;
showOnlyUnread: boolean;
}
@@ -32,7 +32,6 @@ export function PaginatedSeriesGrid({
currentPage,
totalPages,
totalElements,
pageSize,
defaultShowOnlyUnread,
showOnlyUnread: initialShowOnlyUnread,
}: PaginatedSeriesGridProps) {
@@ -41,7 +40,8 @@ export function PaginatedSeriesGrid({
const searchParams = useSearchParams();
const [isChangingPage, setIsChangingPage] = useState(false);
const [showOnlyUnread, setShowOnlyUnread] = useState(initialShowOnlyUnread);
const [isCompact, setIsCompact] = useState(searchParams.get("compact") === "true");
const { isCompact, itemsPerPage, handleCompactToggle, handlePageSizeChange } =
useDisplayPreferences();
const { t } = useTranslate();
const updateUrlParams = async (updates: Record<string, string | null>) => {
@@ -78,7 +78,7 @@ export function PaginatedSeriesGrid({
}, [defaultShowOnlyUnread, pathname, router, searchParams]);
const handlePageChange = async (page: number) => {
await updateUrlParams({ page: page.toString(), compact: isCompact.toString() });
await updateUrlParams({ page: page.toString() });
};
const handleUnreadFilter = async () => {
@@ -87,30 +87,30 @@ export function PaginatedSeriesGrid({
await updateUrlParams({
page: "1",
unread: newUnreadState ? "true" : "false",
compact: isCompact.toString(),
});
};
const handleCompactToggle = async () => {
const handleCompactToggleClick = async () => {
const newCompactState = !isCompact;
setIsCompact(newCompactState);
await handleCompactToggle(newCompactState);
await updateUrlParams({
page: "1",
compact: newCompactState.toString(),
});
};
const handlePageSizeChange = async (value: string) => {
const handlePageSizeChangeClick = async (value: string) => {
const size = parseInt(value);
await handlePageSizeChange(size);
await updateUrlParams({
page: "1",
size: value,
compact: isCompact.toString(),
});
};
// Calculate start and end indices for display
const startIndex = (currentPage - 1) * pageSize + 1;
const endIndex = Math.min(currentPage * pageSize, totalElements);
const startIndex = (currentPage - 1) * itemsPerPage + 1;
const endIndex = Math.min(currentPage * itemsPerPage, totalElements);
const getShowingText = () => {
if (!totalElements) return t("series.empty");
@@ -130,7 +130,7 @@ export function PaginatedSeriesGrid({
</div>
<div className="flex items-center gap-2">
<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]">
<LayoutList className="h-4 w-4 mr-2" />
<SelectValue />
@@ -142,7 +142,7 @@ export function PaginatedSeriesGrid({
</SelectContent>
</Select>
<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"
>
{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,
required: false,
},
displayMode: {
compact: {
type: Boolean,
default: false,
},
itemsPerPage: {
type: Number,
default: 20,
enum: [20, 50, 100],
},
},
},
{
timestamps: true,
@@ -35,6 +46,8 @@ const preferencesSchema = new mongoose.Schema(
// Force la conversion en booléen
ret.showOnlyUnread = Boolean(ret.showOnlyUnread);
ret.debug = Boolean(ret.debug);
ret.displayMode = ret.displayMode || { compact: false, itemsPerPage: 20 };
ret.displayMode.compact = Boolean(ret.displayMode.compact);
return ret;
},
},
@@ -49,8 +62,12 @@ preferencesSchema.pre("save", function (next) {
if (this.debug === undefined) {
this.debug = false;
}
if (!this.displayMode) {
this.displayMode = { compact: false, itemsPerPage: 20 };
}
this.showOnlyUnread = Boolean(this.showOnlyUnread);
this.debug = Boolean(this.debug);
this.displayMode.compact = Boolean(this.displayMode.compact);
next();
});
@@ -63,6 +80,12 @@ preferencesSchema.pre("findOneAndUpdate", function (next) {
if ("debug" in update.$set) {
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();
});

View File

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