From 56c0275db01c011f56bc6e88b414ff3d251b450c Mon Sep 17 00:00:00 2001 From: Pijus Kamandulis Date: Sat, 19 Oct 2024 11:58:02 +0300 Subject: [PATCH] Added loaders --- src/components/Button.tsx | 8 +++- src/components/Loader.tsx | 48 +++++++++++++++++++ .../forms/CreateEstimationSessionForm.tsx | 13 +++-- src/components/icons/LoaderIcon.tsx | 24 ++++++++++ src/components/icons/index.ts | 3 +- src/components/index.ts | 14 +++--- src/main.tsx | 3 +- src/pages/Estimation/Estimation.tsx | 6 +-- .../Estimation/components/EditTicketForm.tsx | 13 +++-- .../components/EstimationResult.tsx | 12 +++-- src/pages/Join.tsx | 4 +- src/pages/Login.tsx | 11 +++-- src/pages/Profile.tsx | 13 +++-- 13 files changed, 141 insertions(+), 31 deletions(-) create mode 100644 src/components/Loader.tsx create mode 100644 src/components/icons/LoaderIcon.tsx diff --git a/src/components/Button.tsx b/src/components/Button.tsx index 3574d56..f89c1c6 100644 --- a/src/components/Button.tsx +++ b/src/components/Button.tsx @@ -1,4 +1,5 @@ import classNames from 'classnames'; +import Loader, { LoaderSize } from './Loader'; enum ButtonColor { Primary = 'primary', @@ -10,6 +11,7 @@ enum ButtonColor { interface ButtonProps extends React.ButtonHTMLAttributes { color?: ButtonColor; fullWidth?: boolean; + isLoading?: boolean; } const Button: React.FC = ({ @@ -17,10 +19,13 @@ const Button: React.FC = ({ color = ButtonColor.Primary, fullWidth = false, disabled = false, + isLoading = false, ...props }) => { + disabled = disabled || isLoading; + const buttonClass = classNames( - 'flex justify-center rounded-md px-3 py-1.5 text-sm font-semibold leading-6 shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2', + 'flex justify-center rounded-md px-3 py-1.5 text-sm font-semibold leading-6 shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 text-center items-center', { 'bg-indigo-600 hover:bg-indigo-500 focus-visible:outline-indigo-600': color === ButtonColor.Primary && !disabled, @@ -38,6 +43,7 @@ const Button: React.FC = ({ return ( ); diff --git a/src/components/Loader.tsx b/src/components/Loader.tsx new file mode 100644 index 0000000..c921aa3 --- /dev/null +++ b/src/components/Loader.tsx @@ -0,0 +1,48 @@ +import classNames from 'classnames'; +import { LoaderIcon } from './icons'; + +export enum LoaderSize { + Small, + Medium, + Big, +} + +interface LoaderProps { + className?: string; + fullHeight?: boolean; + center?: boolean; + size?: LoaderSize; +} + +const Loader: React.FC = ({ + className, + fullHeight = false, + center = false, + size = LoaderSize.Medium, +}) => { + const containerClassName = classNames( + { + ['flex items-center justify-center']: center, + ['h-full']: fullHeight, + }, + className, + ); + + const loaderClassName = classNames( + { + ['h-4 w-4']: size === LoaderSize.Small, + ['h-8 w-8']: size === LoaderSize.Medium, + ['h-12 w-12']: size === LoaderSize.Big, + }, + 'inline animate-spin fill-blue-600 text-gray-200 dark:text-gray-600', + ); + + return ( +
+ + Loading... +
+ ); +}; + +export default Loader; diff --git a/src/components/forms/CreateEstimationSessionForm.tsx b/src/components/forms/CreateEstimationSessionForm.tsx index c6857c5..c2d7ec6 100644 --- a/src/components/forms/CreateEstimationSessionForm.tsx +++ b/src/components/forms/CreateEstimationSessionForm.tsx @@ -56,9 +56,16 @@ const CreateEstimationSessionForm: React.FC< /> )} - [state.canSubmit]}> - {([canSubmit]) => ( - )} diff --git a/src/components/icons/LoaderIcon.tsx b/src/components/icons/LoaderIcon.tsx new file mode 100644 index 0000000..47aeff2 --- /dev/null +++ b/src/components/icons/LoaderIcon.tsx @@ -0,0 +1,24 @@ +import React from 'react'; + +const LoaderIcon: React.FC> = (props) => ( + +); + +export default LoaderIcon; diff --git a/src/components/icons/index.ts b/src/components/icons/index.ts index 2377854..513b002 100644 --- a/src/components/icons/index.ts +++ b/src/components/icons/index.ts @@ -1,3 +1,4 @@ import PencilIcon from './PencilIcon'; +import LoaderIcon from './LoaderIcon'; -export { PencilIcon }; +export { PencilIcon, LoaderIcon }; diff --git a/src/components/index.ts b/src/components/index.ts index 74f6990..a706c49 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -1,16 +1,18 @@ -import Input from './Input'; import Button, { ButtonColor } from './Button'; -import GridList from './GridList'; import Card from './Card'; -import Drawer from './Drawer'; import CreateEstimationSessionForm from './forms/CreateEstimationSessionForm'; +import Drawer from './Drawer'; +import GridList from './GridList'; +import Input from './Input'; +import Loader from './Loader'; export { - Input, Button, ButtonColor, - GridList, Card, - Drawer, CreateEstimationSessionForm, + Drawer, + GridList, + Input, + Loader, }; diff --git a/src/main.tsx b/src/main.tsx index 54e0fb6..19be276 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -18,6 +18,7 @@ import Estimation from './pages/Estimation/Estimation'; import Header from './components/Header'; import Profile from './pages/Profile'; import Join from './pages/Join'; +import { Loader } from './components'; interface RouterContext { userContext: UserContextType; @@ -108,7 +109,7 @@ const InnerApp = () => { const userContext = useUser(); return userContext.isLoading ? ( -

Loading...

+ ) : ( ); diff --git a/src/pages/Estimation/Estimation.tsx b/src/pages/Estimation/Estimation.tsx index 7b66422..76bea8f 100644 --- a/src/pages/Estimation/Estimation.tsx +++ b/src/pages/Estimation/Estimation.tsx @@ -4,7 +4,7 @@ import { getRouteApi } from '@tanstack/react-router'; import TaskSidebar from './components/TaskSidebar'; import VoteSelection from './components/VoteSelection'; import VoteList from './components/VoteList'; -import { Drawer } from '../../components'; +import { Drawer, Loader } from '../../components'; import EditTicketForm from './components/EditTicketForm'; import PlayerList from './components/PlayerList'; import HtmlEmbed from '../../components/HtmlEmbed'; @@ -22,8 +22,8 @@ const Estimation: React.FC = () => { useEffect(() => estimationState?.setSessionId(sessionId), [sessionId]); - if (!estimationState?.currentSessionData) { - return null; // TODO: Add a loader + if (estimationState?.currentSessionData?.id !== sessionId) { + return ; } const { diff --git a/src/pages/Estimation/components/EditTicketForm.tsx b/src/pages/Estimation/components/EditTicketForm.tsx index 748ad78..dc513a5 100644 --- a/src/pages/Estimation/components/EditTicketForm.tsx +++ b/src/pages/Estimation/components/EditTicketForm.tsx @@ -81,9 +81,16 @@ const EditTicketForm: React.FC = ({ /> )} - [state.canSubmit]}> - {([canSubmit]) => ( - )} diff --git a/src/pages/Estimation/components/EstimationResult.tsx b/src/pages/Estimation/components/EstimationResult.tsx index 1803ceb..c5e4ed9 100644 --- a/src/pages/Estimation/components/EstimationResult.tsx +++ b/src/pages/Estimation/components/EstimationResult.tsx @@ -81,9 +81,15 @@ const EstimationResult: React.FC = ({ /> )} - [state.canSubmit]}> - {([canSubmit]) => ( - )} diff --git a/src/pages/Join.tsx b/src/pages/Join.tsx index fa409ba..a12953f 100644 --- a/src/pages/Join.tsx +++ b/src/pages/Join.tsx @@ -5,6 +5,7 @@ import { SessionInviteInfo, } from '../lib/functions/estimationSessionInvite'; import { getRouteApi } from '@tanstack/react-router'; +import { Loader } from '../components'; const route = getRouteApi('/_authenticated/join/$sessionId'); @@ -40,8 +41,7 @@ const Join = () => { }; if (!sessionInfo || isLoading) { - // TODO: add loader - return

Loading...

; + return ; } if (!sessionInfo.success) { diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx index 73c281b..6d31eb8 100644 --- a/src/pages/Login.tsx +++ b/src/pages/Login.tsx @@ -65,13 +65,14 @@ const Login = () => { )} - [state.canSubmit]}> - {([canSubmit]) => ( + [state.canSubmit, state.isSubmitting]} + > + {([canSubmit, isSubmitting]) => (
- {/* TODO: Add loader when [state.isSubmitting] */}
)}