Merge branch 'main' into Feature/Game-Card-Sources

This commit is contained in:
Shisuys
2025-03-13 13:47:54 -03:00
committed by GitHub
31 changed files with 256 additions and 5 deletions

View File

@@ -10,6 +10,8 @@ export interface ConfirmationModalProps extends Omit<ModalProps, "children"> {
onConfirm: () => void;
onCancel?: () => void;
buttonsIsDisabled?: boolean;
}
export function ConfirmationModal({
@@ -18,6 +20,7 @@ export function ConfirmationModal({
descriptionText,
onConfirm,
onCancel,
buttonsIsDisabled = false,
...props
}: ConfirmationModalProps) {
const handleCancelClick = () => {
@@ -38,7 +41,11 @@ export function ConfirmationModal({
<Button theme="outline" onClick={handleCancelClick}>
{cancelButtonLabel}
</Button>
<Button theme="danger" onClick={onConfirm}>
<Button
theme="danger"
disabled={buttonsIsDisabled}
onClick={onConfirm}
>
{confirmButtonLabel}
</Button>
</div>

View File

@@ -53,4 +53,9 @@
text-decoration: none;
}
}
&__remove_all_sources_button {
display: flex;
justify-content: flex-end;
}
}

View File

@@ -1,10 +1,20 @@
import { useContext, useEffect, useState } from "react";
import { TextField, Button, Badge } from "@renderer/components";
import {
TextField,
Button,
Badge,
ConfirmationModal,
} from "@renderer/components";
import { useTranslation } from "react-i18next";
import type { DownloadSource } from "@types";
import { NoEntryIcon, PlusCircleIcon, SyncIcon } from "@primer/octicons-react";
import {
NoEntryIcon,
PlusCircleIcon,
SyncIcon,
XIcon,
} from "@primer/octicons-react";
import { AddDownloadSourceModal } from "./add-download-source-modal";
import { useAppDispatch, useRepacks, useToast } from "@renderer/hooks";
import { DownloadSourceStatus } from "@shared";
@@ -16,6 +26,10 @@ import { setFilters, clearFilters } from "@renderer/features";
import "./settings-download-sources.scss";
export function SettingsDownloadSources() {
const [
showConfirmationDeleteAllSourcesModal,
setShowConfirmationDeleteAllSourcesModal,
] = useState(false);
const [showAddDownloadSourceModal, setShowAddDownloadSourceModal] =
useState(false);
const [downloadSources, setDownloadSources] = useState<DownloadSource[]>([]);
@@ -23,6 +37,7 @@ export function SettingsDownloadSources() {
useState(false);
const [isRemovingDownloadSource, setIsRemovingDownloadSource] =
useState(false);
const [isFetchingSources, setIsFetchingSources] = useState(true);
const { sourceUrl, clearSourceUrl } = useContext(settingsContext);
@@ -41,6 +56,9 @@ export function SettingsDownloadSources() {
.sortBy("createdAt")
.then((sources) => {
setDownloadSources(sources.reverse());
})
.finally(() => {
setIsFetchingSources(false);
});
};
@@ -68,6 +86,25 @@ export function SettingsDownloadSources() {
};
};
const handleRemoveAllDownloadSources = () => {
setIsRemovingDownloadSource(true);
const id = crypto.randomUUID();
const channel = new BroadcastChannel(`download_sources:delete_all:${id}`);
downloadSourcesWorker.postMessage(["DELETE_ALL_DOWNLOAD_SOURCES", id]);
channel.onmessage = () => {
showSuccessToast(t("removed_download_sources"));
getDownloadSources();
setIsRemovingDownloadSource(false);
setShowConfirmationDeleteAllSourcesModal(false);
channel.close();
updateRepacks();
};
};
const handleAddDownloadSource = async () => {
await getDownloadSources();
showSuccessToast(t("added_download_source"));
@@ -115,6 +152,17 @@ export function SettingsDownloadSources() {
onClose={handleModalClose}
onAddDownloadSource={handleAddDownloadSource}
/>
<ConfirmationModal
cancelButtonLabel={t("cancel_button_confirmation_delete_all_sources")}
confirmButtonLabel={t("confirm_button_confirmation_delete_all_sources")}
descriptionText={t("description_confirmation_delete_all_sources")}
clickOutsideToClose={false}
onConfirm={handleRemoveAllDownloadSources}
visible={showConfirmationDeleteAllSourcesModal}
title={t("title_confirmation_delete_all_sources")}
onClose={() => setShowConfirmationDeleteAllSourcesModal(false)}
buttonsIsDisabled={isRemovingDownloadSource}
/>
<p>{t("download_sources_description")}</p>
@@ -144,6 +192,20 @@ export function SettingsDownloadSources() {
</Button>
</div>
{!isFetchingSources && downloadSources.length >= 2 && (
<div className="settings-download-sources__remove_all_sources_button">
<Button
type="button"
theme="danger"
onClick={() => setShowConfirmationDeleteAllSourcesModal(true)}
disabled={isRemovingDownloadSource}
>
<XIcon />
{t("button_delete_all_sources")}
</Button>
</div>
)}
<ul className="settings-download-sources__list">
{downloadSources.map((downloadSource) => (
<li

View File

@@ -23,7 +23,8 @@ type Payload =
| ["IMPORT_DOWNLOAD_SOURCE", string]
| ["DELETE_DOWNLOAD_SOURCE", number]
| ["VALIDATE_DOWNLOAD_SOURCE", string]
| ["SYNC_DOWNLOAD_SOURCES", string];
| ["SYNC_DOWNLOAD_SOURCES", string]
| ["DELETE_ALL_DOWNLOAD_SOURCES", string];
export type SteamGamesByLetter = Record<string, { id: string; name: string }[]>;
@@ -114,6 +115,13 @@ const deleteDownloadSource = async (id: number) => {
});
};
const deleteAllDowloadSources = async () => {
await db.transaction("rw", repacksTable, downloadSourcesTable, async () => {
await repacksTable.clear();
await downloadSourcesTable.clear();
});
};
self.onmessage = async (event: MessageEvent<Payload>) => {
const [type, data] = event.data;
@@ -132,6 +140,14 @@ self.onmessage = async (event: MessageEvent<Payload>) => {
});
}
if (type === "DELETE_ALL_DOWNLOAD_SOURCES") {
await deleteAllDowloadSources();
const channel = new BroadcastChannel(`download_sources:delete_all:${data}`);
channel.postMessage(true);
}
if (type === "DELETE_DOWNLOAD_SOURCE") {
await deleteDownloadSource(data);