mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 16:13:15 +00:00
# Conflicts: # components/contacts/contacts-app.tsx # components/email/__tests__/composer-discard.test.tsx # components/email/calendar-invitation-banner.tsx # components/email/email-composer.tsx # components/mail/mail-app.tsx # components/pro/pro-compose-tab-body.tsx # components/pro/pro-email-tab-body.tsx # components/ui/__tests__/avatar.test.tsx # components/ui/avatar.tsx # hooks/use-mailbox-drop.ts # lib/__tests__/calendar-alerts.test.ts # lib/__tests__/jmap-calendar-tasks.test.ts # lib/__tests__/jmap-send-threading.test.ts # lib/demo/demo-client.ts # lib/demo/fixtures/calendars.ts # lib/jmap/client-interface.ts # lib/jmap/client.ts # lib/web-push.ts # stores/__tests__/contact-store.test.ts # stores/__tests__/email-store-thread-key.test.ts # stores/calendar-store.ts # stores/contact-store.ts # stores/email-store.ts
113 lines
3.7 KiB
TypeScript
113 lines
3.7 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useCallback } from "react";
|
|
import { useTranslations } from "next-intl";
|
|
import { Upload, Download, Loader2 } from "@/components/icons";
|
|
import { Button } from "@/components/ui/button";
|
|
import { SettingsSection, SettingItem, ToggleSwitch } from "./settings-section";
|
|
import { ContactImportDialog } from "@/components/contacts/contact-import-dialog";
|
|
import { exportContacts, useContactExportBusy } from "@/components/contacts/contact-export";
|
|
import { useContactStore } from "@/stores/contact-store";
|
|
import { useAuthStore } from "@/stores/auth-store";
|
|
import { useSettingsStore } from "@/stores/settings-store";
|
|
import { toast } from "@/stores/toast-store";
|
|
|
|
export function ContactsSettings() {
|
|
const t = useTranslations("contacts");
|
|
const tSettings = useTranslations("settings.contacts");
|
|
const { client } = useAuthStore();
|
|
const {
|
|
contacts,
|
|
supportsSync,
|
|
importContacts,
|
|
} = useContactStore();
|
|
const groupContactsByLetter = useSettingsStore((s) => s.groupContactsByLetter);
|
|
const sortContactsByLastName = useSettingsStore((s) => s.sortContactsByLastName);
|
|
const updateSetting = useSettingsStore((s) => s.updateSetting);
|
|
const [showImport, setShowImport] = useState(false);
|
|
const exporting = useContactExportBusy();
|
|
|
|
const individuals = contacts.filter(c => c.kind !== "group");
|
|
|
|
const handleImport = useCallback(async (importedContacts: import("@/lib/jmap/types").ContactCard[]) => {
|
|
return importContacts(
|
|
supportsSync && client ? client : null,
|
|
importedContacts
|
|
);
|
|
}, [supportsSync, client, importContacts]);
|
|
|
|
const handleExport = async () => {
|
|
if (individuals.length > 0 && await exportContacts(individuals)) {
|
|
toast.success(t("export.success", { count: individuals.length }));
|
|
}
|
|
};
|
|
|
|
if (showImport) {
|
|
return (
|
|
<div className="border border-border rounded-lg overflow-hidden" style={{ minHeight: 400 }}>
|
|
<ContactImportDialog
|
|
existingContacts={contacts}
|
|
onImport={handleImport}
|
|
onClose={() => setShowImport(false)}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<SettingsSection
|
|
id="contacts"
|
|
title={tSettings("title")}
|
|
description={tSettings("description")}
|
|
>
|
|
<SettingItem
|
|
label={tSettings("group_by_letter_label")}
|
|
description={tSettings("group_by_letter_description")}
|
|
>
|
|
<ToggleSwitch
|
|
checked={groupContactsByLetter}
|
|
onChange={(checked) => updateSetting("groupContactsByLetter", checked)}
|
|
/>
|
|
</SettingItem>
|
|
|
|
<SettingItem
|
|
label={tSettings("sort_by_last_name_label")}
|
|
description={tSettings("sort_by_last_name_description")}
|
|
>
|
|
<ToggleSwitch
|
|
checked={sortContactsByLastName}
|
|
onChange={(checked) => updateSetting("sortContactsByLastName", checked)}
|
|
/>
|
|
</SettingItem>
|
|
|
|
<SettingItem
|
|
label={tSettings("import_label")}
|
|
description={tSettings("import_description")}
|
|
>
|
|
<Button variant="outline" size="sm" onClick={() => setShowImport(true)}>
|
|
<Upload className="w-4 h-4 me-2" />
|
|
{t("import.title")}
|
|
</Button>
|
|
</SettingItem>
|
|
|
|
<SettingItem
|
|
label={tSettings("export_label")}
|
|
description={tSettings("export_description")}
|
|
>
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
onClick={handleExport}
|
|
disabled={individuals.length === 0 || exporting}
|
|
aria-busy={exporting}
|
|
>
|
|
{exporting
|
|
? <Loader2 className="w-4 h-4 me-2 animate-spin" />
|
|
: <Download className="w-4 h-4 me-2" />}
|
|
{exporting ? t("export.exporting") : t("export.title")}
|
|
</Button>
|
|
</SettingItem>
|
|
</SettingsSection>
|
|
);
|
|
}
|