mirror of
https://github.com/idanoo/autobrr
synced 2025-07-23 16:59:12 +00:00
Feature: Toast Notification System (#25)
* Add react-hot-toaster to dependencies * Enable TailwindCSS 'jit' mode * Add Toast component * Add Toaster context for react-hot-toast * Add toast notification for queries, form validation fix * Add new animations for Toast component * fix: nickserv account validation Co-authored-by: Ludvig Lundgren <hello@ludviglundgren.se>
This commit is contained in:
parent
00f956870b
commit
11fcf1ead9
15 changed files with 195 additions and 14 deletions
|
@ -17,6 +17,9 @@ import {
|
|||
RadioFieldsetWide,
|
||||
} from "../../components/inputs/wide";
|
||||
|
||||
import { toast } from 'react-hot-toast'
|
||||
import Toast from '../../components/notifications/Toast';
|
||||
|
||||
interface DownloadClientSelectProps {
|
||||
name: string;
|
||||
clients: DownloadClient[];
|
||||
|
@ -135,6 +138,8 @@ function FilterActionAddForm({ filter, isOpen, toggle, clients }: props) {
|
|||
{
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries(["filter", filter.id]);
|
||||
toast.custom((t) => <Toast type="success" body="Action was added" t={t} />)
|
||||
|
||||
sleep(500).then(() => toggle());
|
||||
},
|
||||
}
|
||||
|
|
|
@ -17,6 +17,10 @@ import {
|
|||
} from "../../components/inputs/wide";
|
||||
import { DownloadClientSelect } from "./FilterActionAddForm";
|
||||
|
||||
import { toast } from 'react-hot-toast'
|
||||
import Toast from '../../components/notifications/Toast';
|
||||
|
||||
|
||||
interface props {
|
||||
filter: Filter;
|
||||
isOpen: boolean;
|
||||
|
@ -38,6 +42,8 @@ function FilterActionUpdateForm({
|
|||
onSuccess: () => {
|
||||
// console.log("add action");
|
||||
queryClient.invalidateQueries(["filter", filter.id]);
|
||||
toast.custom((t) => <Toast type="success" body={`${filter.name} was updated successfully`} t={t} />)
|
||||
|
||||
sleep(1500);
|
||||
|
||||
toggle();
|
||||
|
|
|
@ -8,12 +8,18 @@ import {Field, Form} from "react-final-form";
|
|||
import DEBUG from "../../components/debug";
|
||||
import APIClient from "../../api/APIClient";
|
||||
|
||||
import { toast } from 'react-hot-toast'
|
||||
import Toast from '../../components/notifications/Toast';
|
||||
|
||||
|
||||
const required = (value: any) => (value ? undefined : 'Required')
|
||||
|
||||
function FilterAddForm({isOpen, toggle}: any) {
|
||||
const mutation = useMutation((filter: Filter) => APIClient.filters.create(filter), {
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries('filter');
|
||||
toast.custom((t) => <Toast type="success" body="Filter was added" t={t} />)
|
||||
|
||||
toggle()
|
||||
}
|
||||
})
|
||||
|
|
|
@ -11,7 +11,8 @@ import { queryClient } from "../../App";
|
|||
import { SwitchGroup, TextFieldWide } from "../../components/inputs";
|
||||
import APIClient from "../../api/APIClient";
|
||||
import { NumberFieldWide, PasswordFieldWide } from "../../components/inputs/wide";
|
||||
|
||||
import { toast } from 'react-hot-toast'
|
||||
import Toast from '../../components/notifications/Toast';
|
||||
interface props {
|
||||
isOpen: boolean;
|
||||
toggle: any;
|
||||
|
@ -28,9 +29,12 @@ function IndexerAddForm({ isOpen, toggle }: props) {
|
|||
const mutation = useMutation((indexer: Indexer) => APIClient.indexers.create(indexer), {
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries(['indexer']);
|
||||
toast.custom((t) => <Toast type="success" body="Indexer was added" t={t} />)
|
||||
sleep(1500)
|
||||
|
||||
toggle()
|
||||
},
|
||||
onError: () => {
|
||||
toast.custom((t) => <Toast type="error" body="Indexer could not be added" t={t} />)
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -12,6 +12,9 @@ import APIClient from "../../api/APIClient";
|
|||
import { queryClient } from "../../App";
|
||||
import { PasswordFieldWide } from "../../components/inputs/wide";
|
||||
|
||||
import { toast } from 'react-hot-toast'
|
||||
import Toast from '../../components/notifications/Toast';
|
||||
|
||||
interface props {
|
||||
isOpen: boolean;
|
||||
toggle: any;
|
||||
|
@ -24,6 +27,7 @@ function IndexerUpdateForm({ isOpen, toggle, indexer }: props) {
|
|||
const mutation = useMutation((indexer: Indexer) => APIClient.indexers.update(indexer), {
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries(['indexer']);
|
||||
toast.custom((t) => <Toast type="success" body={`${indexer.name} was updated successfully`} t={t}/>)
|
||||
sleep(1500)
|
||||
|
||||
toggle()
|
||||
|
@ -33,6 +37,7 @@ function IndexerUpdateForm({ isOpen, toggle, indexer }: props) {
|
|||
const deleteMutation = useMutation((id: number) => APIClient.indexers.delete(id), {
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries(['indexer']);
|
||||
toast.custom((t) => <Toast type="success" body={`${indexer.name} was deleted.`} t={t}/>)
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -14,17 +14,31 @@ import {classNames} from "../../styles/utils";
|
|||
import APIClient from "../../api/APIClient";
|
||||
import { NumberFieldWide, PasswordFieldWide } from "../../components/inputs/wide";
|
||||
|
||||
import { toast } from 'react-hot-toast';
|
||||
import Toast from '../../components/notifications/Toast';
|
||||
|
||||
type FormValues = {
|
||||
name: string
|
||||
server: string
|
||||
nickserv: {
|
||||
account: string
|
||||
}
|
||||
port: number
|
||||
}
|
||||
|
||||
function IrcNetworkAddForm({isOpen, toggle}: any) {
|
||||
const mutation = useMutation((network: Network) => APIClient.irc.createNetwork(network), {
|
||||
onSuccess: data => {
|
||||
onSuccess: (data) => {
|
||||
queryClient.invalidateQueries(['networks']);
|
||||
toast.custom((t) => <Toast type="success" body="IRC Network added" t={t} />)
|
||||
toggle()
|
||||
}
|
||||
},
|
||||
onError: () => {
|
||||
toast.custom((t) => <Toast type="error" body="IRC Network could not be added" t={t}/>)
|
||||
},
|
||||
})
|
||||
|
||||
const onSubmit = (data: any) => {
|
||||
console.log(data)
|
||||
|
||||
// easy way to split textarea lines into array of strings for each newline.
|
||||
// parse on the field didn't really work.
|
||||
let cmds = data.connect_commands && data.connect_commands.length > 0 ? data.connect_commands.replace(/\r\n/g,"\n").split("\n") : [];
|
||||
|
@ -35,22 +49,34 @@ function IrcNetworkAddForm({isOpen, toggle}: any) {
|
|||
};
|
||||
|
||||
const validate = (values: any) => {
|
||||
const errors = {} as any;
|
||||
const errors = {
|
||||
nickserv: {
|
||||
account: null,
|
||||
}
|
||||
} as any;
|
||||
|
||||
if (!values.name) {
|
||||
errors.name = "Required";
|
||||
}
|
||||
|
||||
if (!values.port) {
|
||||
errors.port = "Required";
|
||||
}
|
||||
|
||||
if (!values.server) {
|
||||
errors.server = "Required";
|
||||
}
|
||||
|
||||
if(!values.nickserv?.account) {
|
||||
errors.nickserv.account = "Required";
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
return (
|
||||
<Transition.Root show={isOpen} as={Fragment}>
|
||||
<Dialog as="div" static className="fixed inset-0 overflow-hidden" open={isOpen} onClose={toggle}>
|
||||
<Dialog as="div" static className="fixed inset-0 overflow-hidden transition-all" open={isOpen} onClose={toggle}>
|
||||
<div className="absolute inset-0 overflow-hidden">
|
||||
<Dialog.Overlay className="absolute inset-0"/>
|
||||
|
||||
|
@ -73,6 +99,9 @@ function IrcNetworkAddForm({isOpen, toggle}: any) {
|
|||
server: "",
|
||||
tls: false,
|
||||
pass: "",
|
||||
nickserv: {
|
||||
account: ""
|
||||
}
|
||||
}}
|
||||
mutators={{
|
||||
...arrayMutators
|
||||
|
@ -119,7 +148,7 @@ function IrcNetworkAddForm({isOpen, toggle}: any) {
|
|||
|
||||
<div>
|
||||
<TextFieldWide name="server" label="Server" placeholder="Address: Eg irc.server.net" required={true} />
|
||||
<NumberFieldWide name="port" label="Port" required={true} />
|
||||
<NumberFieldWide name="port" label="Port" placeholder="Eg 6667" required={true} />
|
||||
|
||||
<div className="py-6 px-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200">
|
||||
<SwitchGroup name="tls" label="TLS"/>
|
||||
|
@ -127,7 +156,7 @@ function IrcNetworkAddForm({isOpen, toggle}: any) {
|
|||
|
||||
<PasswordFieldWide name="pass" label="Password" help="Network password" />
|
||||
|
||||
<TextFieldWide name="nickserv.account" label="NickServ Account" required={true} />
|
||||
<TextFieldWide name="nickserv.account" label="NickServ Account" placeholder="NickServ Account" required={true} />
|
||||
<PasswordFieldWide name="nickserv.password" label="NickServ Password" />
|
||||
|
||||
<PasswordFieldWide name="invite_command" label="Invite command" />
|
||||
|
|
|
@ -16,12 +16,16 @@ import { DeleteModal } from "../../components/modals";
|
|||
import APIClient from "../../api/APIClient";
|
||||
import { NumberFieldWide, PasswordFieldWide } from "../../components/inputs/wide";
|
||||
|
||||
import { toast } from 'react-hot-toast';
|
||||
import Toast from '../../components/notifications/Toast';
|
||||
|
||||
|
||||
function IrcNetworkUpdateForm({ isOpen, toggle, network }: any) {
|
||||
const [deleteModalIsOpen, toggleDeleteModal] = useToggle(false)
|
||||
|
||||
const mutation = useMutation((network: Network) => APIClient.irc.updateNetwork(network), {
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries(['networks']);
|
||||
toast.custom((t) => <Toast type="success" body={`${network.name} was updated successfully`} t={t} />)
|
||||
toggle()
|
||||
}
|
||||
})
|
||||
|
@ -29,6 +33,8 @@ function IrcNetworkUpdateForm({ isOpen, toggle, network }: any) {
|
|||
const deleteMutation = useMutation((id: number) => APIClient.irc.deleteNetwork(id), {
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries(['networks']);
|
||||
toast.custom((t) => <Toast type="success" body={`${network.name} was deleted.`} t={t} />)
|
||||
|
||||
toggle()
|
||||
}
|
||||
})
|
||||
|
@ -52,7 +58,11 @@ function IrcNetworkUpdateForm({ isOpen, toggle, network }: any) {
|
|||
};
|
||||
|
||||
const validate = (values: any) => {
|
||||
const errors = {} as any;
|
||||
const errors = {
|
||||
nickserv: {
|
||||
account: null,
|
||||
}
|
||||
} as any;
|
||||
|
||||
if (!values.name) {
|
||||
errors.name = "Required";
|
||||
|
@ -66,7 +76,7 @@ function IrcNetworkUpdateForm({ isOpen, toggle, network }: any) {
|
|||
errors.port = "Required";
|
||||
}
|
||||
|
||||
if (!values.nickserv.account) {
|
||||
if(!values.nickserv?.account) {
|
||||
errors.nickserv.account = "Required";
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,9 @@ import { DownloadClientTypeOptions } from "../../../domain/constants";
|
|||
import { RadioFieldsetWide } from "../../../components/inputs/wide";
|
||||
import { componentMap } from "./shared";
|
||||
|
||||
import { toast } from 'react-hot-toast'
|
||||
import Toast from '../../../components/notifications/Toast';
|
||||
|
||||
function DownloadClientAddForm({ isOpen, toggle }: any) {
|
||||
const [isTesting, setIsTesting] = useState(false);
|
||||
const [isSuccessfulTest, setIsSuccessfulTest] = useState(false);
|
||||
|
@ -27,8 +30,13 @@ function DownloadClientAddForm({ isOpen, toggle }: any) {
|
|||
{
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries(["downloadClients"]);
|
||||
toast.custom((t) => <Toast type="success" body="Client was added" t={t} />)
|
||||
|
||||
toggle();
|
||||
},
|
||||
onError: () => {
|
||||
toast.custom((t) => <Toast type="error" body="Client could not be added" t={t} />)
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -53,6 +61,7 @@ function DownloadClientAddForm({ isOpen, toggle }: any) {
|
|||
});
|
||||
},
|
||||
onError: (error) => {
|
||||
console.log('not added')
|
||||
setIsTesting(false);
|
||||
setIsErrorTest(true);
|
||||
sleep(2500).then(() => {
|
||||
|
|
|
@ -16,6 +16,10 @@ import { componentMap } from "./shared";
|
|||
import { RadioFieldsetWide } from "../../../components/inputs/wide";
|
||||
import { DeleteModal } from "../../../components/modals";
|
||||
|
||||
import { toast } from 'react-hot-toast'
|
||||
import Toast from '../../../components/notifications/Toast';
|
||||
|
||||
|
||||
function DownloadClientUpdateForm({ client, isOpen, toggle }: any) {
|
||||
const [isTesting, setIsTesting] = useState(false);
|
||||
const [isSuccessfulTest, setIsSuccessfulTest] = useState(false);
|
||||
|
@ -27,7 +31,7 @@ function DownloadClientUpdateForm({ client, isOpen, toggle }: any) {
|
|||
{
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries(["downloadClients"]);
|
||||
|
||||
toast.custom((t) => <Toast type="success" body={`${client.name} was updated successfully`} t={t} />)
|
||||
toggle();
|
||||
},
|
||||
}
|
||||
|
@ -38,6 +42,7 @@ function DownloadClientUpdateForm({ client, isOpen, toggle }: any) {
|
|||
{
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries();
|
||||
toast.custom((t) => <Toast type="success" body={`${client.name} was deleted.`} t={t}/>)
|
||||
toggleDeleteModal();
|
||||
},
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue