✨ Start on error handling
♻ Use TypedDocumentNode's instead of apollo-react-typescript codegen
💄 Add toast
This commit is contained in:
1 parent
ed82ca3891
commit
0a435d3224
21 files changed
+565
-117
No files matched your search
@@ -0,0 +1,5 @@
|
||||
.toast {
|
||||
position: absolute;
|
||||
bottom: 32px;
|
||||
right: 32px;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import { Toast as BSToast } from "bootstrap";
|
||||
import clsx from "clsx";
|
||||
import React, { useEffect, useRef } from "react";
|
||||
|
||||
import styles from "./Toast.module.css";
|
||||
import { useToast } from "./ToastProvider";
|
||||
|
||||
export const Toast: React.FC = () => {
|
||||
const ref = useRef<HTMLInputElement>(null);
|
||||
const { visible, showToast, message } = useToast();
|
||||
|
||||
const classes = clsx("toast align-items-center text-white bg-primary border-0", styles.toast);
|
||||
|
||||
useEffect(() => {
|
||||
if (!ref.current) return;
|
||||
const bsToast = BSToast.getInstance(ref.current) || new BSToast(ref.current);
|
||||
|
||||
if (visible) {
|
||||
bsToast?.show();
|
||||
} else if (!visible) {
|
||||
bsToast?.hide();
|
||||
}
|
||||
return () => bsToast?.hide();
|
||||
}, [visible]);
|
||||
|
||||
return (
|
||||
<div ref={ref} className={classes} role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div className="d-flex">
|
||||
<div className="toast-body">{message}</div>
|
||||
<button
|
||||
type="button"
|
||||
className="btn-close btn-close-white me-2 m-auto"
|
||||
data-bs-dismiss="toast"
|
||||
aria-label="Close"
|
||||
onClick={() => showToast(message)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,45 @@
|
||||
import React, { ReactNode, useContext, useState } from "react";
|
||||
|
||||
interface ToastProps {
|
||||
visible: boolean;
|
||||
message: string;
|
||||
showToast: (message: string) => void;
|
||||
hide: () => void;
|
||||
}
|
||||
|
||||
const defaultState = {
|
||||
visible: false,
|
||||
message: "",
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
showToast: () => {},
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
hide: () => {},
|
||||
};
|
||||
|
||||
const ToastContext = React.createContext<ToastProps>(defaultState);
|
||||
|
||||
type ToastProviderProps = {
|
||||
children: ReactNode;
|
||||
};
|
||||
export const ToastProvider: React.FC<ToastProviderProps> = ({ children }) => {
|
||||
const [visible, setVisible] = useState(defaultState.visible);
|
||||
const [message, setMessage] = useState("");
|
||||
|
||||
const showToast = (newMessage: string) => {
|
||||
setMessage(newMessage);
|
||||
if (!visible) {
|
||||
setVisible(true);
|
||||
setTimeout(() => {
|
||||
setVisible(false);
|
||||
setMessage("");
|
||||
}, 3000);
|
||||
}
|
||||
};
|
||||
const hide = () => {
|
||||
setVisible(true);
|
||||
setMessage("");
|
||||
};
|
||||
return <ToastContext.Provider value={{ visible, showToast, message, hide }}>{children}</ToastContext.Provider>;
|
||||
};
|
||||
|
||||
export const useToast = (): ToastProps => useContext(ToastContext);
|
||||
Reference in new issue
Block a user