refactor: switched to sonner from shadcn toast

This commit is contained in:
2025-08-11 12:38:44 +05:30
parent 8b32824bb9
commit 5908579c2f
6 changed files with 76 additions and 139 deletions

View File

@@ -1,6 +1,5 @@
import { ThemeProvider } from "@/providers/themeProvider";
import { TooltipProvider } from "@/components/ui/tooltip";
import { Toaster } from "@/components/ui/toaster";
import { AppContext } from "@/providers/appContextProvider";
import { DownloadState } from "@/types/download";
import { invoke } from "@tauri-apps/api/core";
@@ -25,11 +24,10 @@ import { useNavigate } from "react-router-dom";
import { platform } from "@tauri-apps/plugin-os";
import { useMacOsRegisterer } from "@/helpers/use-macos-registerer";
import useAppUpdater from "@/helpers/use-app-updater";
import { useToast } from "@/hooks/use-toast";
import { Toaster as Sonner } from "@/components/ui/sonner";
import { toast } from "sonner";
export default function App({ children }: { children: React.ReactNode }) {
const { toast } = useToast();
const { data: downloadStates, isSuccess: isSuccessFetchingDownloadStates } = useFetchAllDownloadStates();
const { data: settings, isSuccess: isSuccessFetchingSettings } = useFetchAllSettings();
const { data: kvPairs, isSuccess: isSuccessFetchingKvPairs } = useFetchAllkVPairs();
@@ -180,10 +178,8 @@ export default function App({ children }: { children: React.ReactNode }) {
let videoMetadata = await fetchVideoMetadata(url, selectedFormat, isPlaylist && playlistIndex && typeof playlistIndex === 'string' ? playlistIndex : undefined);
if (!videoMetadata) {
console.error('Failed to fetch video metadata');
toast({
title: 'Download Failed',
description: 'yt-dlp failed to fetch video metadata. Please try again later.',
variant: 'destructive',
toast.error("Download Failed", {
description: "yt-dlp failed to fetch video metadata. Please try again later.",
});
return;
}
@@ -865,10 +861,8 @@ export default function App({ children }: { children: React.ReactNode }) {
// show a toast and pause the download when yt-dlp exits unexpectedly
useEffect(() => {
if (isErrored && !isErrorExpected) {
toast({
title: "Download Failed",
toast.error("Download Failed", {
description: "yt-dlp exited unexpectedly. Please try again later",
variant: "destructive",
});
if (erroredDownloadId) {
downloadStatusUpdater.mutate({ download_id: erroredDownloadId, download_status: 'paused' }, {
@@ -904,7 +898,7 @@ export default function App({ children }: { children: React.ReactNode }) {
<ThemeProvider defaultTheme={APP_THEME || "system"} storageKey="vite-ui-theme">
<TooltipProvider delayDuration={1000}>
{children}
<Toaster />
<Sonner closeButton />
</TooltipProvider>
</ThemeProvider>
</AppContext.Provider>

View File

@@ -15,6 +15,12 @@ const Toaster = ({ ...props }: ToasterProps) => {
"--normal-border": "var(--border)",
} as React.CSSProperties
}
toastOptions={{
classNames: {
toast: "group",
icon: "group-data-[type=error]:!text-red-500 group-data-[type=success]:!text-green-500 group-data-[type=warning]:!text-amber-500 group-data-[type=info]:!text-sky-500",
},
}}
{...props}
/>
)

View File

@@ -1,11 +1,10 @@
import { useToast } from "@/hooks/use-toast";
import { toast } from "sonner";
import { useResetSettings, useSaveSettingsKey } from "@/services/mutations";
import { useSettingsPageStatesStore } from "@/services/store";
import { useQueryClient } from "@tanstack/react-query";
import { invoke } from "@tauri-apps/api/core";
export function useSettings() {
const { toast } = useToast();
const queryClient = useQueryClient();
const setSettingsKey = useSettingsPageStatesStore(state => state.setSettingsKey);
const resetSettingsState = useSettingsPageStatesStore(state => state.resetSettings);
@@ -22,10 +21,8 @@ export function useSettings() {
onError: (error) => {
console.error("Error saving settings key:", error);
queryClient.invalidateQueries({ queryKey: ["settings"] });
toast({
title: "Failed to update settings",
toast.error("Failed to update settings", {
description: `Failed to update ${key}`,
variant: "destructive",
});
}
});
@@ -39,26 +36,21 @@ export function useSettings() {
resetSettingsState();
console.log("Settings reset successfully");
queryClient.invalidateQueries({ queryKey: ["settings"] });
toast({
title: "Settings reset successfully",
toast.success("Settings reset successfully", {
description: "All settings have been reset to default.",
});
} catch (error) {
console.error("Error resetting settings:", error);
toast({
title: "Failed to reset settings",
toast.error("Failed to reset settings", {
description: "Failed to reset settings to default.",
variant: "destructive",
});
return;
}
},
onError: (error) => {
console.error("Error resetting settings:", error);
toast({
title: "Failed to reset settings",
toast.error("Failed to reset settings", {
description: "Failed to reset settings to default.",
variant: "destructive",
});
}
});

View File

@@ -5,7 +5,7 @@ import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Separator } from "@/components/ui/separator";
import { useToast } from "@/hooks/use-toast";
import { toast } from "sonner";
import { useAppContext } from "@/providers/appContextProvider";
import { useCurrentVideoMetadataStore, useDownloaderPageStatesStore, useSettingsPageStatesStore } from "@/services/store";
import { determineFileType, fileFormatFilter, formatBitrate, formatDurationString, formatFileSize, formatReleaseDate, formatYtStyleCount, isObjEmpty, sortByBitrate } from "@/utils";
@@ -35,7 +35,6 @@ const searchFormSchema = z.object({
export default function DownloaderPage() {
const { fetchVideoMetadata, startDownload } = useAppContext();
const { toast } = useToast();
const videoUrl = useCurrentVideoMetadataStore((state) => state.videoUrl);
const videoMetadata = useCurrentVideoMetadataStore((state) => state.videoMetadata);
@@ -226,10 +225,8 @@ export default function DownloaderPage() {
if (!metadata || (metadata._type !== 'video' && metadata._type !== 'playlist') || (metadata && metadata._type === 'video' && metadata.formats.length <= 0) || (metadata && metadata._type === 'playlist' && metadata.entries.length <= 0)) {
const showSearchError = useCurrentVideoMetadataStore.getState().showSearchError;
if (showSearchError) {
toast({
title: 'Oops! No results found',
description: 'The provided URL does not contain any downloadable content or you are not connected to the internet. Please check the URL, your network connection and try again.',
variant: "destructive"
toast.error("Oops! No results found", {
description: "The provided URL does not contain any downloadable content or you are not connected to the internet. Please check the URL, your network connection and try again.",
});
}
}
@@ -307,20 +304,16 @@ export default function DownloaderPage() {
// If URL is invalid, just reset the flag
setAutoSubmitSearch(false);
setRequestedUrl('');
toast({
title: 'Invalid URL',
description: 'The provided URL is not valid.',
variant: "destructive"
toast.error("Invalid URL", {
description: "The provided URL is not valid.",
});
}
} else {
// If metadata is loading, just reset the flag
setAutoSubmitSearch(false);
setRequestedUrl('');
toast({
title: 'Search in progress',
description: 'Search in progress, try again later.',
variant: "destructive"
toast.info("Search in progress", {
description: "There's a search in progress, Please try again later.",
});
}
} else {
@@ -941,10 +934,8 @@ export default function DownloaderPage() {
// });
} catch (error) {
console.error('Download failed to start:', error);
toast({
title: 'Failed to Start Download',
description: 'There was an error initiating the download.',
variant: "destructive"
toast.error("Failed to Start Download", {
description: "There was an error initiating the download."
});
} finally {
setIsStartingDownload(false);

View File

@@ -4,7 +4,7 @@ import { AspectRatio } from "@/components/ui/aspect-ratio";
import { Button } from "@/components/ui/button";
import { Progress } from "@/components/ui/progress";
import { Separator } from "@/components/ui/separator";
import { useToast } from "@/hooks/use-toast";
import { toast } from "sonner";
import { useAppContext } from "@/providers/appContextProvider";
import { useDownloadActionStatesStore, useDownloadStatesStore, useLibraryPageStatesStore } from "@/services/store";
import { formatBitrate, formatCodec, formatDurationString, formatFileSize, formatSecToTimeString, formatSpeed } from "@/utils";
@@ -21,7 +21,6 @@ import Heading from "@/components/heading";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Badge } from "@/components/ui/badge";
export default function LibraryPage() {
const activeTab = useLibraryPageStatesStore(state => state.activeTab);
const setActiveTab = useLibraryPageStatesStore(state => state.setActiveTab);
@@ -34,7 +33,6 @@ export default function LibraryPage() {
const setIsDeleteFileChecked = useDownloadActionStatesStore(state => state.setIsDeleteFileChecked);
const { pauseDownload, resumeDownload, cancelDownload } = useAppContext()
const { toast } = useToast();
const queryClient = useQueryClient();
const downloadStateDeleter = useDeleteDownloadState();
@@ -49,24 +47,19 @@ export default function LibraryPage() {
if (filePath && await fs.exists(filePath)) {
try {
await invoke('open_file_with_app', { filePath: filePath, appName: app }).then(() => {
toast({
title: 'Opening file',
toast.info("Opening file", {
description: `Opening the file with ${app ? app : 'default app'}.`,
})
});
} catch (e) {
console.error(e);
toast({
title: 'Failed to open file',
description: 'An error occurred while trying to open the file.',
variant: "destructive"
toast.error("Failed to open file", {
description: "An error occurred while trying to open the file.",
})
}
} else {
toast({
title: 'File unavailable',
description: 'The file you are trying to open does not exist.',
variant: "destructive"
toast.info("File unavailable", {
description: "The file you are trying to open does not exist.",
})
}
}
@@ -88,18 +81,15 @@ export default function LibraryPage() {
onSuccess: (data) => {
console.log("Download State deleted successfully:", data);
queryClient.invalidateQueries({ queryKey: ['download-states'] });
toast({
title: 'Removed from downloads',
description: 'The download has been removed successfully.',
})
toast.success("Removed from downloads", {
description: "The download has been removed successfully.",
});
},
onError: (error) => {
console.error("Failed to delete download state:", error);
toast({
title: 'Failed to remove download',
description: 'An error occurred while trying to remove the download.',
variant: "destructive"
})
toast.error("Failed to remove download", {
description: "An error occurred while trying to remove the download.",
});
}
})
}
@@ -112,26 +102,21 @@ export default function LibraryPage() {
await pauseDownload(state);
} catch (e) {
console.error(e);
toast({
title: 'Failed to stop download',
toast.error("Failed to stop download", {
description: `An error occurred while trying to stop the download for ${state.title}.`,
variant: "destructive"
});
} finally {
setIsPausingDownload(state.download_id, false);
}
}
if (ongoingDownloads.length === 0) {
toast({
title: 'Stopped ongoing downloads',
description: 'All ongoing downloads have been stopped successfully.',
toast.success("Stopped ongoing downloads", {
description: "All ongoing downloads have been stopped successfully.",
});
}
} else {
toast({
title: 'No ongoing downloads',
description: 'There are no ongoing downloads to stop.',
variant: "destructive"
toast.info("No ongoing downloads", {
description: "There are no ongoing downloads to stop.",
});
}
}
@@ -374,16 +359,13 @@ export default function LibraryPage() {
setIsResumingDownload(state.download_id, true);
try {
await resumeDownload(state)
// toast({
// title: 'Resumed Download',
// description: 'Download resumed, it will re-start shortly.',
// toast.success("Resumed Download", {
// description: "Download resumed, it will re-start shortly.",
// })
} catch (e) {
console.error(e);
toast({
title: 'Failed to Resume Download',
description: 'An error occurred while trying to resume the download.',
variant: "destructive"
toast.error("Failed to Resume Download", {
description: "An error occurred while trying to resume the download.",
})
} finally {
setIsResumingDownload(state.download_id, false);
@@ -411,16 +393,13 @@ export default function LibraryPage() {
setIsPausingDownload(state.download_id, true);
try {
await pauseDownload(state)
// toast({
// title: 'Paused Download',
// description: 'Download paused successfully.',
// toast.success("Paused Download", {
// description: "Download paused successfully.",
// })
} catch (e) {
console.error(e);
toast({
title: 'Failed to Pause Download',
description: 'An error occurred while trying to pause the download.',
variant: "destructive"
toast.error("Failed to Pause Download", {
description: "An error occurred while trying to pause the download."
})
} finally {
setIsPausingDownload(state.download_id, false);
@@ -448,16 +427,13 @@ export default function LibraryPage() {
setIsCancelingDownload(state.download_id, true);
try {
await cancelDownload(state)
toast({
title: 'Canceled Download',
description: 'Download canceled successfully.',
toast.success("Canceled Download", {
description: "Download canceled successfully.",
})
} catch (e) {
console.error(e);
toast({
title: 'Failed to Cancel Download',
description: 'An error occurred while trying to cancel the download.',
variant: "destructive"
toast.error("Failed to Cancel Download", {
description: "An error occurred while trying to cancel the download.",
})
} finally {
setIsCancelingDownload(state.download_id, false);

View File

@@ -6,7 +6,7 @@ import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrig
import { Switch } from "@/components/ui/switch";
import { Label } from "@/components/ui/label";
import { Button } from "@/components/ui/button";
import { useToast } from "@/hooks/use-toast";
import { toast } from "sonner";
import { ArrowDownToLine, ArrowRight, BrushCleaning, EthernetPort, ExternalLink, FileVideo, Folder, FolderOpen, Info, Loader2, LucideIcon, Monitor, Moon, Radio, RotateCcw, RotateCw, Sun, Terminal, WandSparkles, Wifi, Wrench } from "lucide-react";
import { cn } from "@/lib/utils";
import { useEffect } from "react";
@@ -65,7 +65,6 @@ const rateLimitSchema = z.object({
});
export default function SettingsPage() {
const { toast } = useToast();
const { setTheme } = useTheme();
const activeTab = useSettingsPageStatesStore(state => state.activeTab);
@@ -123,17 +122,14 @@ export default function SettingsPage() {
const openLink = async (url: string, app: string | null) => {
try {
await invoke('open_file_with_app', { filePath: url, appName: app }).then(() => {
toast({
title: 'Opening Link',
toast.info("Opening link", {
description: `Opening link with ${app ? app : 'default app'}.`,
})
});
} catch (e) {
console.error(e);
toast({
title: 'Failed to open link',
description: 'An error occurred while trying to open the link.',
variant: "destructive"
toast.error("Failed to open link", {
description: "An error occurred while trying to open the link.",
})
}
}
@@ -148,20 +144,16 @@ export default function SettingsPage() {
await fs.remove(filePath);
}
}
toast({
title: "Temporary Downloads Cleaned",
toast.success("Temporary Downloads Cleaned", {
description: "All temporary downloads have been successfully cleaned up.",
});
} catch (e) {
toast({
title: "Temporary Downloads Cleanup Failed",
toast.error("Temporary Downloads Cleanup Failed", {
description: "An error occurred while trying to clean up temporary downloads. Please try again.",
variant: "destructive",
});
}
} else {
toast({
title: "No Temporary Downloads",
toast.info("No Temporary Downloads", {
description: "There are no temporary downloads to clean up.",
});
}
@@ -180,16 +172,13 @@ export default function SettingsPage() {
function handleProxyUrlSubmit(values: z.infer<typeof proxyUrlSchema>) {
try {
saveSettingsKey('proxy_url', values.url);
toast({
title: "Proxy URL updated",
toast.success("Proxy URL updated", {
description: `Proxy URL changed to ${values.url}`,
});
} catch (error) {
console.error("Error changing proxy URL:", error);
toast({
title: "Failed to change proxy URL",
description: "Please try again.",
variant: "destructive",
toast.error("Failed to change proxy URL", {
description: "An error occurred while trying to change the proxy URL. Please try again.",
});
}
}
@@ -207,16 +196,13 @@ export default function SettingsPage() {
function handleRateLimitSubmit(values: z.infer<typeof rateLimitSchema>) {
try {
saveSettingsKey('rate_limit', values.rate_limit);
toast({
title: "Rate Limit updated",
toast.success("Rate Limit updated", {
description: `Rate Limit changed to ${values.rate_limit} bytes/s`,
});
} catch (error) {
console.error("Error changing rate limit:", error);
toast({
title: "Failed to change rate limit",
description: "Please try again.",
variant: "destructive",
toast.error("Failed to change rate limit", {
description: "An error occurred while trying to change the rate limit. Please try again.",
});
}
}
@@ -245,16 +231,13 @@ export default function SettingsPage() {
}
});
saveSettingsKey('websocket_port', updatedConfig.port);
toast({
title: "Websocket port updated",
toast.success("Websocket port updated", {
description: `Websocket port changed to ${values.port}`,
});
} catch (error) {
console.error("Error changing websocket port:", error);
toast({
title: "Failed to change websocket port",
description: "Please try again.",
variant: "destructive",
toast.error("Failed to change websocket port", {
description: "An error occurred while trying to change the websocket port. Please try again.",
});
} finally {
setIsChangingWebSocketPort(false);
@@ -492,10 +475,8 @@ export default function SettingsPage() {
}
} catch (error) {
console.error("Error selecting folder:", error);
toast({
title: "Failed to select folder",
description: "Please try again.",
variant: "destructive",
toast.error("Failed to select folder", {
description: "An error occurred while trying to select the download folder. Please try again.",
});
}
}}
@@ -739,16 +720,13 @@ export default function SettingsPage() {
setIsRestartingWebSocketServer(true);
try {
await invoke("restart_websocket_server");
toast({
title: "Websocket server restarted",
toast.success("Websocket server restarted", {
description: "Websocket server restarted successfully.",
});
} catch (error) {
console.error("Error restarting websocket server:", error);
toast({
title: "Failed to restart websocket server",
description: "Please try again.",
variant: "destructive",
toast.error("Failed to restart websocket server", {
description: "An error occurred while trying to restart the websocket server. Please try again.",
});
} finally {
setIsRestartingWebSocketServer(false);