✨ Start on error handling

♻ Use TypedDocumentNode's instead of apollo-react-typescript codegen
💄 Add toast
This commit is contained in:
nikolark committed 2021-11-06 21:49:28 +01:00
1 parent ed82ca3891
commit 0a435d3224
21 files changed
+565 -117

No files matched your search

+5
View File
@@ -0,0 +1,5 @@
.toast {
position: absolute;
bottom: 32px;
right: 32px;
}
+40
View File
@@ -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>
);
};
+45
View File
@@ -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);