mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-06-16 13:34:04 +08:00
8669879ad0
Introduce a one-time welcome dialog that explains CC Switch's workflow to new users: how their existing config is preserved as a "default" provider and how the bundled "Official" preset enables one-click revert. Upgrade users are excluded by checking is_providers_empty() at startup and never see the dialog. Persistence follows the existing *_confirmed convention in AppSettings (proxy/usage/stream_check/failover), stored in settings.json. The field is only written when the user explicitly clicks the confirm button, keeping its semantics strictly about user acknowledgement. Also adds two reusable DAO helpers: - Database::is_providers_empty for fresh-install detection, using EXISTS(SELECT 1) for a short-circuit query. - Database::get_bool_flag accepting "true" | "1", with init_default_official_providers migrated to use it. Dialog copy in zh/en/ja uses conditional phrasing so it stays accurate whether or not existing live config was found.
68 lines
2.3 KiB
TypeScript
68 lines
2.3 KiB
TypeScript
import { useTranslation } from "react-i18next";
|
|
import { useQueryClient } from "@tanstack/react-query";
|
|
import { Sparkles } from "lucide-react";
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from "@/components/ui/dialog";
|
|
import { Button } from "@/components/ui/button";
|
|
import { useSettingsQuery } from "@/lib/query";
|
|
import { settingsApi } from "@/lib/api";
|
|
|
|
/** 首次运行欢迎提示:仅当后端启动阶段保留 firstRunNoticeConfirmed 为空时弹出。 */
|
|
export function FirstRunNoticeDialog() {
|
|
const { t } = useTranslation();
|
|
const queryClient = useQueryClient();
|
|
const { data: settings } = useSettingsQuery();
|
|
|
|
// 后端启动时已经决定好要不要弹:条件不满足的话字段会立即被写成 true,
|
|
// 所以前端这里只需要判空即可——完全对齐 streamCheckConfirmed 等既有 flag 的模式。
|
|
const isOpen = settings != null && settings.firstRunNoticeConfirmed !== true;
|
|
|
|
const handleAcknowledge = async () => {
|
|
if (!settings) return;
|
|
try {
|
|
const { webdavSync: _, ...rest } = settings;
|
|
await settingsApi.save({ ...rest, firstRunNoticeConfirmed: true });
|
|
await queryClient.invalidateQueries({ queryKey: ["settings"] });
|
|
} catch (error) {
|
|
console.error("Failed to save firstRunNoticeConfirmed:", error);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Dialog
|
|
open={isOpen}
|
|
onOpenChange={(open) => {
|
|
if (!open) void handleAcknowledge();
|
|
}}
|
|
>
|
|
<DialogContent className="max-w-md" zIndex="top">
|
|
<DialogHeader>
|
|
<DialogTitle className="flex items-center gap-2">
|
|
<Sparkles className="h-5 w-5 text-blue-500" />
|
|
{t("firstRunNotice.title")}
|
|
</DialogTitle>
|
|
</DialogHeader>
|
|
<div className="space-y-3 px-6 py-5">
|
|
<DialogDescription className="whitespace-pre-line leading-relaxed">
|
|
{t("firstRunNotice.bodyDefault")}
|
|
</DialogDescription>
|
|
<DialogDescription className="whitespace-pre-line leading-relaxed">
|
|
{t("firstRunNotice.bodyOfficial")}
|
|
</DialogDescription>
|
|
</div>
|
|
<DialogFooter>
|
|
<Button onClick={handleAcknowledge}>
|
|
{t("firstRunNotice.confirm")}
|
|
</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|