mirror of
https://github.com/felipegcoutinho/openmonetis.git
synced 2026-05-09 11:01:45 +00:00
154 lines
4.2 KiB
TypeScript
154 lines
4.2 KiB
TypeScript
import { RiDeleteBinLine } from "@remixicon/react";
|
|
import Image from "next/image";
|
|
import { Button } from "@/shared/components/ui/button";
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from "@/shared/components/ui/select";
|
|
import { resolveLogoSrc } from "@/shared/lib/logo";
|
|
import type { InboxItem, InboxStatus } from "./types";
|
|
|
|
const DEFAULT_INBOX_APP_LOGO = "/avatars/default_icon.png";
|
|
|
|
function findMatchingLogo(
|
|
sourceAppName: string | null,
|
|
appLogoMap: Record<string, string>,
|
|
): string | null {
|
|
if (!sourceAppName) return null;
|
|
const appName = sourceAppName.toLowerCase();
|
|
if (appLogoMap[appName]) return resolveLogoSrc(appLogoMap[appName]);
|
|
for (const [name, logo] of Object.entries(appLogoMap)) {
|
|
if (name.includes(appName) || appName.includes(name)) {
|
|
return resolveLogoSrc(logo);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
type InboxBulkActionsProps = {
|
|
status: InboxStatus;
|
|
items: InboxItem[];
|
|
activeApp: string | null;
|
|
appFilterOptions: string[];
|
|
selectedIds: string[];
|
|
allSelected: boolean;
|
|
appLogoMap: Record<string, string>;
|
|
onAppChange: (app: string) => void;
|
|
onToggleSelectAll: () => void;
|
|
onSelectionBulkRequest: (status: InboxStatus) => void;
|
|
onBulkDeleteRequest: (status: "processed" | "discarded") => void;
|
|
};
|
|
|
|
export function InboxBulkActions({
|
|
status,
|
|
items,
|
|
activeApp,
|
|
appFilterOptions,
|
|
selectedIds,
|
|
allSelected,
|
|
appLogoMap,
|
|
onAppChange,
|
|
onToggleSelectAll,
|
|
onSelectionBulkRequest,
|
|
onBulkDeleteRequest,
|
|
}: InboxBulkActionsProps) {
|
|
const getAppLogo = (appName: string | null) =>
|
|
findMatchingLogo(appName, appLogoMap) ?? DEFAULT_INBOX_APP_LOGO;
|
|
|
|
const appFilter =
|
|
appFilterOptions.length > 0 ? (
|
|
<Select value={activeApp ?? "all"} onValueChange={onAppChange}>
|
|
<SelectTrigger className="w-[190px]">
|
|
<SelectValue>
|
|
<span className="flex min-w-0 items-center gap-2">
|
|
<div className="relative size-5 shrink-0 overflow-hidden rounded-full">
|
|
<Image
|
|
src={
|
|
activeApp ? getAppLogo(activeApp) : DEFAULT_INBOX_APP_LOGO
|
|
}
|
|
alt=""
|
|
fill
|
|
sizes="20px"
|
|
className="object-cover"
|
|
/>
|
|
</div>
|
|
<span className="truncate">{activeApp ?? "Todos"}</span>
|
|
</span>
|
|
</SelectValue>
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="all">
|
|
<span className="flex items-center gap-2">
|
|
<div className="relative size-5 shrink-0 overflow-hidden rounded-full">
|
|
<Image
|
|
src={DEFAULT_INBOX_APP_LOGO}
|
|
alt=""
|
|
fill
|
|
sizes="20px"
|
|
className="object-cover"
|
|
/>
|
|
</div>
|
|
<span>Todos</span>
|
|
</span>
|
|
</SelectItem>
|
|
{appFilterOptions.map((app) => (
|
|
<SelectItem key={app} value={app}>
|
|
<span className="flex min-w-0 items-center gap-2">
|
|
<div className="relative size-5 shrink-0 overflow-hidden rounded-full">
|
|
<Image
|
|
src={getAppLogo(app)}
|
|
alt=""
|
|
fill
|
|
sizes="20px"
|
|
className="object-cover"
|
|
/>
|
|
</div>
|
|
<span className="truncate">{app}</span>
|
|
</span>
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
) : null;
|
|
|
|
return (
|
|
<div className="mb-4 flex flex-wrap items-center gap-2">
|
|
{appFilter}
|
|
{items.length > 0 ? (
|
|
<div className="ml-auto flex items-center gap-2">
|
|
<Button variant="outline" size="sm" onClick={onToggleSelectAll}>
|
|
{allSelected ? "Cancelar seleção" : "Selecionar página"}
|
|
</Button>
|
|
{selectedIds.length > 0 && (
|
|
<Button
|
|
variant="destructive"
|
|
size="sm"
|
|
onClick={() => onSelectionBulkRequest(status)}
|
|
>
|
|
<RiDeleteBinLine className="mr-1.5 size-4" />
|
|
{status === "pending"
|
|
? `Descartar selecionados (${selectedIds.length})`
|
|
: `Excluir selecionados (${selectedIds.length})`}
|
|
</Button>
|
|
)}
|
|
{(status === "processed" || status === "discarded") && (
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
onClick={() => onBulkDeleteRequest(status)}
|
|
>
|
|
<RiDeleteBinLine className="mr-1.5 size-4" />
|
|
{status === "processed"
|
|
? "Limpar processados"
|
|
: "Limpar descartados"}
|
|
</Button>
|
|
)}
|
|
</div>
|
|
) : null}
|
|
</div>
|
|
);
|
|
}
|