feat: integrate display preferences for pagination and compact view in series grid
This commit is contained in:
@@ -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 ? (
|
||||||
|
|||||||
60
src/hooks/useDisplayPreferences.ts
Normal file
60
src/hooks/useDisplayPreferences.ts
Normal 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,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user