From fb065fb552b7946b5b87507d91fb975a143ddb02 Mon Sep 17 00:00:00 2001 From: nidheesh-m-vakharia Date: Thu, 25 Jul 2024 10:30:27 -0700 Subject: [PATCH 01/19] commit --- package-lock.json | 11 ++ package.json | 1 + src/app/admin/[type]/page.js | 2 + .../admin/services/timer/ProgressBar.jsx | 15 ++ src/components/admin/services/timer/Timer.jsx | 180 ++++++++++++++++++ .../admin/services/timer/TimerControls.jsx | 68 +++++++ .../admin/services/timer/TimerDisplay.jsx | 14 ++ .../admin/services/timer/TimerEditMode.jsx | 31 +++ .../admin/services/timer/TimerPage.jsx | 55 ++++++ .../admin/services/timer/TimerStatus.jsx | 23 +++ .../admin/services/timer/Tooltip.jsx | 12 ++ src/components/ui/input-otp.jsx | 62 ++++++ src/data/Navigation.js | 6 + tailwind.config.js | 5 + 14 files changed, 485 insertions(+) mode change 100644 => 100755 package-lock.json create mode 100644 src/components/admin/services/timer/ProgressBar.jsx create mode 100644 src/components/admin/services/timer/Timer.jsx create mode 100644 src/components/admin/services/timer/TimerControls.jsx create mode 100644 src/components/admin/services/timer/TimerDisplay.jsx create mode 100644 src/components/admin/services/timer/TimerEditMode.jsx create mode 100644 src/components/admin/services/timer/TimerPage.jsx create mode 100644 src/components/admin/services/timer/TimerStatus.jsx create mode 100644 src/components/admin/services/timer/Tooltip.jsx create mode 100644 src/components/ui/input-otp.jsx diff --git a/package-lock.json b/package-lock.json old mode 100644 new mode 100755 index 20185b44c..16966b19a --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "firebase": "^10.8.0", "firebase-admin": "^11.11.0", "gray-matter": "^4.0.3", + "input-otp": "^1.2.4", "lucide-react": "^0.408.0", "next": "^14.0.1", "next-auth": "^4.24.4", @@ -7548,6 +7549,16 @@ "fast-loops": "^1.1.3" } }, + "node_modules/input-otp": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/input-otp/-/input-otp-1.2.4.tgz", + "integrity": "sha512-md6rhmD+zmMnUh5crQNSQxq3keBRYvE3odbr4Qb9g2NWzQv9azi+t1a3X4TBTbh98fsGHgEEJlzbe1q860uGCA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, "node_modules/internal-slot": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", diff --git a/package.json b/package.json index d5ef395e8..ec4963213 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "firebase": "^10.8.0", "firebase-admin": "^11.11.0", "gray-matter": "^4.0.3", + "input-otp": "^1.2.4", "lucide-react": "^0.408.0", "next": "^14.0.1", "next-auth": "^4.24.4", diff --git a/src/app/admin/[type]/page.js b/src/app/admin/[type]/page.js index 0a65f7c54..1be21a4e8 100644 --- a/src/app/admin/[type]/page.js +++ b/src/app/admin/[type]/page.js @@ -19,6 +19,7 @@ import Volunteers from "@/components/admin/dashboards/Volunteers"; import Leads from "@/components/admin/dashboards/Leads"; import Fault from "@/utils/error"; import Settings from "@/components/admin/services/settings/Settings"; +import TimerPage from "@/components/admin/services/timer/TimerPage"; const Page = ({ params, searchParams }) => { const components = { @@ -40,6 +41,7 @@ const Page = ({ params, searchParams }) => { teams: , volunteers: , leads: , + timer: , }; const capitalizeFirstLetter = (word) => { diff --git a/src/components/admin/services/timer/ProgressBar.jsx b/src/components/admin/services/timer/ProgressBar.jsx new file mode 100644 index 000000000..d6eefe2c5 --- /dev/null +++ b/src/components/admin/services/timer/ProgressBar.jsx @@ -0,0 +1,15 @@ +const ProgressBar = ({ totalSeconds, ogTotalSeconds }) => { + const progress = ogTotalSeconds + ? ((ogTotalSeconds - totalSeconds) / ogTotalSeconds) * 100 + : 0; + return ( +
+
+
+ ); +}; + +export default ProgressBar; diff --git a/src/components/admin/services/timer/Timer.jsx b/src/components/admin/services/timer/Timer.jsx new file mode 100644 index 000000000..2e7be4245 --- /dev/null +++ b/src/components/admin/services/timer/Timer.jsx @@ -0,0 +1,180 @@ +import { useState, useEffect, useRef } from "react"; +import TimerDisplay from "./TimerDisplay"; +import TimerStatus from "./TimerStatus"; +import TimerControls from "./TimerControls"; +import TimerEditMode from "./TimerEditMode"; +import ProgressBar from "./ProgressBar"; +import { FaChevronDown, FaChevronUp } from "react-icons/fa"; + +export default function Timer({ name, onRemove }) { + const [paused, setPaused] = useState(true); + const [totalSeconds, setTotalSeconds] = useState(0); + const [isComplete, setIsComplete] = useState(false); + const [isEditMode, setEditMode] = useState(false); + const [ogTotalSeconds, setOgTotalSeconds] = useState(0); + const [editedValue, setEditedValue] = useState(""); + const [invalid, setInvalid] = useState(true); + const [collapsed, setCollapsed] = useState(false); + + const timerRef = useRef(null); + + const [time, setTime] = useState({ + hours: 0, + minutes: 0, + seconds: 0, + }); + + useEffect(() => { + resetTimer(); + setEditedValue(""); + }, [isEditMode]); + + useEffect(() => { + const calculateTime = (seconds) => { + return { + hours: Math.floor((seconds % 86400) / 3600), + minutes: Math.floor((seconds % 3600) / 60), + seconds: seconds % 60, + }; + }; + + setTime(calculateTime(totalSeconds)); + + if (totalSeconds === 0) { + setPaused(true); + setIsComplete(true); + return; + } + if (isComplete) { + return; + } + if (paused) { + return; + } + + timerRef.current = setTimeout(() => { + setTotalSeconds((prevSeconds) => prevSeconds - 1); + }, 1000); + + return () => clearTimeout(timerRef.current); + }, [paused, isComplete, totalSeconds]); + + const pauseTimer = () => { + setPaused(true); + }; + + const resumeTimer = () => { + if (isComplete) { + setPaused(true); + } else { + setPaused(false); + } + }; + + const resetTimer = () => { + setTotalSeconds(ogTotalSeconds); + setIsComplete(false); + setPaused(true); + }; + + const openEditMode = () => { + setEditMode(true); + setEditedValue(""); + setInvalid(true); + }; + + const numberToDate = (num) => { + const dateString = num.toString().padEnd(6, "0"); + return { + hours: parseInt(dateString.substr(0, 2)), + minutes: parseInt(dateString.substr(2, 2)), + seconds: parseInt(dateString.substr(4, 2)), + }; + }; + + const saveChanges = () => { + const dateObject = numberToDate(editedValue); + + if (dateObject.minutes > 59 || dateObject.seconds > 59) { + setInvalid(true); + return; + } + setEditMode(false); + + const total = + dateObject.hours * 3600 + dateObject.minutes * 60 + dateObject.seconds; + setOgTotalSeconds(total); + setTotalSeconds(total); + }; + + const inputOnChange = (value) => { + if (value.length === 6) { + const dateObject = numberToDate(value); + if (dateObject.minutes > 59 || dateObject.seconds > 59) { + setInvalid(true); + } else { + setInvalid(false); + } + } else { + setInvalid(true); + } + setEditedValue(value); + }; + + const discardChanges = () => { + setEditMode(false); + }; + + const toggleCollapse = () => { + setCollapsed((prev) => !prev); + }; + + return ( +
+
+ + +
+ +
+
+ + {!collapsed && ( + <> + {isEditMode ? ( + + ) : ( + + )} + + + )} + +
+ ); +} diff --git a/src/components/admin/services/timer/TimerControls.jsx b/src/components/admin/services/timer/TimerControls.jsx new file mode 100644 index 000000000..b6147060d --- /dev/null +++ b/src/components/admin/services/timer/TimerControls.jsx @@ -0,0 +1,68 @@ +import { + FaPlay, + FaPause, + FaUndo, + FaTrashAlt, + FaPen, + FaCheck, + FaTimes, +} from "react-icons/fa"; +import Tooltip from "./Tooltip"; + +const TimerControls = ({ + isEditMode, + paused, + isComplete, + resumeTimer, + pauseTimer, + openEditMode, + resetTimer, + onRemove, + saveChanges, + discardChanges, + invalid, + collapsed, +}) => ( +
+ {!isEditMode ? ( + <> + {paused || isComplete ? ( + + + + ) : ( + + + + )} + {!collapsed && ( + <> + + + + + + + + )} + + + + + ) : ( + <> + + {}} + className={`text-2xl mx-1 ${invalid ? "text-gray-500" : ""}`} + /> + + + + + + )} +
+); + +export default TimerControls; diff --git a/src/components/admin/services/timer/TimerDisplay.jsx b/src/components/admin/services/timer/TimerDisplay.jsx new file mode 100644 index 000000000..376c9a3b3 --- /dev/null +++ b/src/components/admin/services/timer/TimerDisplay.jsx @@ -0,0 +1,14 @@ +const TimerDisplay = ({ time }) => ( +
+ {["Hours", "Minutes", "Seconds"].map((label, idx) => ( +
+
+ {time[idx === 0 ? "hours" : idx === 1 ? "minutes" : "seconds"]} +
+
{label}
+
+ ))} +
+); + +export default TimerDisplay; diff --git a/src/components/admin/services/timer/TimerEditMode.jsx b/src/components/admin/services/timer/TimerEditMode.jsx new file mode 100644 index 000000000..4a26de851 --- /dev/null +++ b/src/components/admin/services/timer/TimerEditMode.jsx @@ -0,0 +1,31 @@ +import { + InputOTP, + InputOTPGroup, + InputOTPSeparator, + InputOTPSlot, +} from "@/components/ui/input-otp"; + +const TimerEditMode = ({ editedValue, inputOnChange }) => ( + inputOnChange(value)} + value={editedValue} + className="mt-4" + > + + + + + + + + + + + + + + +); + +export default TimerEditMode; diff --git a/src/components/admin/services/timer/TimerPage.jsx b/src/components/admin/services/timer/TimerPage.jsx new file mode 100644 index 000000000..2278d3589 --- /dev/null +++ b/src/components/admin/services/timer/TimerPage.jsx @@ -0,0 +1,55 @@ +import { useState } from "react"; +import Timer from "./Timer"; +import { v4 as uuidv4 } from "uuid"; + +export default function TimerPage() { + const [timerArray, setTimerArray] = useState([]); + + const addTimer = () => { + setTimerArray([ + ...timerArray, + { + id: uuidv4(), + }, + ]); + }; + + const clearAll = () => { + setTimerArray([]); + }; + + const deleteTime = (id) => { + setTimerArray(timerArray.filter((timer) => timer.id !== id)); + }; + + return ( +
+
+

Timer

+ + +
+
+ {timerArray.length === 0 ? ( +
+ No timers +
+ ) : ( + timerArray.map((timer) => ( + deleteTime(timer.id)} /> + )) + )} +
+
+ ); +} diff --git a/src/components/admin/services/timer/TimerStatus.jsx b/src/components/admin/services/timer/TimerStatus.jsx new file mode 100644 index 000000000..82bf0182f --- /dev/null +++ b/src/components/admin/services/timer/TimerStatus.jsx @@ -0,0 +1,23 @@ +const TimerStatus = ({ isComplete, paused }) => { + if (isComplete) { + return ( +
+ Completed +
+ ); + } + if (paused) { + return ( +
+ Not Running +
+ ); + } + return ( +
+ Running +
+ ); +}; + +export default TimerStatus; diff --git a/src/components/admin/services/timer/Tooltip.jsx b/src/components/admin/services/timer/Tooltip.jsx new file mode 100644 index 000000000..4c43cc08c --- /dev/null +++ b/src/components/admin/services/timer/Tooltip.jsx @@ -0,0 +1,12 @@ +const Tooltip = ({ children, text }) => { + return ( +
+ {children} +
+ {text} +
+
+ ); +}; + +export default Tooltip; diff --git a/src/components/ui/input-otp.jsx b/src/components/ui/input-otp.jsx new file mode 100644 index 000000000..adf3249af --- /dev/null +++ b/src/components/ui/input-otp.jsx @@ -0,0 +1,62 @@ +"use client"; + +import * as React from "react"; +import { OTPInput, OTPInputContext } from "input-otp"; +import { Dot } from "lucide-react"; + +import { cn } from "@/utils/utils"; + +const InputOTP = React.forwardRef( + ({ className, containerClassName, ...props }, ref) => ( + + ) +); +InputOTP.displayName = "InputOTP"; + +const InputOTPGroup = React.forwardRef(({ className, ...props }, ref) => ( +
+)); +InputOTPGroup.displayName = "InputOTPGroup"; + +const InputOTPSlot = React.forwardRef(({ index, className, ...props }, ref) => { + const inputOTPContext = React.useContext(OTPInputContext); + const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index]; + + return ( +
+ {char} + {hasFakeCaret && ( +
+
+
+ )} +
+ ); +}); +InputOTPSlot.displayName = "InputOTPSlot"; + +const InputOTPSeparator = React.forwardRef(({ ...props }, ref) => ( +
+ +
+)); +InputOTPSeparator.displayName = "InputOTPSeparator"; + +export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator }; diff --git a/src/data/Navigation.js b/src/data/Navigation.js index 805c17a85..25f0c109e 100644 --- a/src/data/Navigation.js +++ b/src/data/Navigation.js @@ -18,6 +18,7 @@ import { import { FaGear } from "react-icons/fa6"; import { AiOutlineQrcode } from "react-icons/ai"; import { SiHandshake } from "react-icons/si"; +import { RxLapTimer } from "react-icons/rx"; import { RiTeamFill } from "react-icons/ri"; import { IoIosPeople } from "react-icons/io"; @@ -126,6 +127,11 @@ export const TABS = { link: "/admin/settings", icon: , }, + { + name: "timer", + link: "/admin/timer", + icon: , + }, ], }, }, diff --git a/tailwind.config.js b/tailwind.config.js index 4a4d6ade7..a4273d34e 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -60,10 +60,15 @@ module.exports = { from: { height: "var(--radix-accordion-content-height)" }, to: { height: "0" }, }, + "caret-blink": { + "0%,70%,100%": { opacity: "1" }, + "20%,50%": { opacity: "0" }, + }, }, animation: { "accordion-down": "accordion-down 0.2s ease-out", "accordion-up": "accordion-up 0.2s ease-out", + "caret-blink": "caret-blink 1.25s ease-out infinite", }, }, }, From 085af178888cad9e6cc2b6cb0d9f075bed89fd7b Mon Sep 17 00:00:00 2001 From: nidheesh-m-vakharia Date: Thu, 25 Jul 2024 18:34:37 -0700 Subject: [PATCH 02/19] fix:variable name change, Icons Change,Progress Bar Chnage --- package-lock.json | 25 +++++++++++++ package.json | 1 + .../admin/services/timer/ProgressBar.jsx | 15 -------- src/components/admin/services/timer/Timer.jsx | 35 +++++++++---------- .../admin/services/timer/TimerEditMode.jsx | 6 ++-- src/components/ui/progress.jsx | 25 +++++++++++++ 6 files changed, 70 insertions(+), 37 deletions(-) delete mode 100644 src/components/admin/services/timer/ProgressBar.jsx create mode 100644 src/components/ui/progress.jsx diff --git a/package-lock.json b/package-lock.json index 16966b19a..e3227a0be 100755 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@radix-ui/react-alert-dialog": "^1.1.1", "@radix-ui/react-checkbox": "^1.1.1", "@radix-ui/react-label": "^2.1.0", + "@radix-ui/react-progress": "^1.1.0", "@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-tabs": "^1.1.0", "@react-email/components": "^0.0.16", @@ -1932,6 +1933,30 @@ } } }, + "node_modules/@radix-ui/react-progress": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.0.tgz", + "integrity": "sha512-aSzvnYpP725CROcxAOEBVZZSIQVQdHgBr2QQFKySsaD14u8dNT0batuXI+AAGDdAHfXH8rbnHmjYFqVJ21KkRg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-primitive": "2.0.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-roving-focus": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.0.tgz", diff --git a/package.json b/package.json index ec4963213..14959b65f 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "@radix-ui/react-alert-dialog": "^1.1.1", "@radix-ui/react-checkbox": "^1.1.1", "@radix-ui/react-label": "^2.1.0", + "@radix-ui/react-progress": "^1.1.0", "@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-tabs": "^1.1.0", "@react-email/components": "^0.0.16", diff --git a/src/components/admin/services/timer/ProgressBar.jsx b/src/components/admin/services/timer/ProgressBar.jsx deleted file mode 100644 index d6eefe2c5..000000000 --- a/src/components/admin/services/timer/ProgressBar.jsx +++ /dev/null @@ -1,15 +0,0 @@ -const ProgressBar = ({ totalSeconds, ogTotalSeconds }) => { - const progress = ogTotalSeconds - ? ((ogTotalSeconds - totalSeconds) / ogTotalSeconds) * 100 - : 0; - return ( -
-
-
- ); -}; - -export default ProgressBar; diff --git a/src/components/admin/services/timer/Timer.jsx b/src/components/admin/services/timer/Timer.jsx index 2e7be4245..8e73b0292 100644 --- a/src/components/admin/services/timer/Timer.jsx +++ b/src/components/admin/services/timer/Timer.jsx @@ -3,15 +3,15 @@ import TimerDisplay from "./TimerDisplay"; import TimerStatus from "./TimerStatus"; import TimerControls from "./TimerControls"; import TimerEditMode from "./TimerEditMode"; -import ProgressBar from "./ProgressBar"; -import { FaChevronDown, FaChevronUp } from "react-icons/fa"; +import { Progress } from "@/components/ui/progress"; +import { ChevronDown, ChevronUp } from "lucide-react"; export default function Timer({ name, onRemove }) { const [paused, setPaused] = useState(true); - const [totalSeconds, setTotalSeconds] = useState(0); + const [total, setTotal] = useState(0); const [isComplete, setIsComplete] = useState(false); const [isEditMode, setEditMode] = useState(false); - const [ogTotalSeconds, setOgTotalSeconds] = useState(0); + const [original, setOriginal] = useState(0); const [editedValue, setEditedValue] = useState(""); const [invalid, setInvalid] = useState(true); const [collapsed, setCollapsed] = useState(false); @@ -38,9 +38,9 @@ export default function Timer({ name, onRemove }) { }; }; - setTime(calculateTime(totalSeconds)); + setTime(calculateTime(total)); - if (totalSeconds === 0) { + if (total === 0) { setPaused(true); setIsComplete(true); return; @@ -53,11 +53,11 @@ export default function Timer({ name, onRemove }) { } timerRef.current = setTimeout(() => { - setTotalSeconds((prevSeconds) => prevSeconds - 1); + setTotal((prevSeconds) => prevSeconds - 1); }, 1000); return () => clearTimeout(timerRef.current); - }, [paused, isComplete, totalSeconds]); + }, [paused, isComplete, total]); const pauseTimer = () => { setPaused(true); @@ -72,7 +72,7 @@ export default function Timer({ name, onRemove }) { }; const resetTimer = () => { - setTotalSeconds(ogTotalSeconds); + setTotal(original); setIsComplete(false); setPaused(true); }; @@ -103,8 +103,8 @@ export default function Timer({ name, onRemove }) { const total = dateObject.hours * 3600 + dateObject.minutes * 60 + dateObject.seconds; - setOgTotalSeconds(total); - setTotalSeconds(total); + setOriginal(total); + setTotal(total); }; const inputOnChange = (value) => { @@ -133,7 +133,7 @@ export default function Timer({ name, onRemove }) {
{isEditMode ? ( - + ) : ( )} )} -
); diff --git a/src/components/admin/services/timer/TimerEditMode.jsx b/src/components/admin/services/timer/TimerEditMode.jsx index 4a26de851..fa0d5c1dc 100644 --- a/src/components/admin/services/timer/TimerEditMode.jsx +++ b/src/components/admin/services/timer/TimerEditMode.jsx @@ -5,11 +5,11 @@ import { InputOTPSlot, } from "@/components/ui/input-otp"; -const TimerEditMode = ({ editedValue, inputOnChange }) => ( +const TimerEditMode = ({ value, OnChange }) => ( inputOnChange(value)} - value={editedValue} + onChange={(value) => OnChange(value)} + value={value} className="mt-4" > diff --git a/src/components/ui/progress.jsx b/src/components/ui/progress.jsx new file mode 100644 index 000000000..d43a1ddf0 --- /dev/null +++ b/src/components/ui/progress.jsx @@ -0,0 +1,25 @@ +"use client"; + +import * as React from "react"; +import * as ProgressPrimitive from "@radix-ui/react-progress"; + +import { cn } from "@/utils/utils"; + +const Progress = React.forwardRef(({ className, value, ...props }, ref) => ( + + + +)); +Progress.displayName = ProgressPrimitive.Root.displayName; + +export { Progress }; From e3fcdd8097f1887c2c0b3a65fedae24d9753693e Mon Sep 17 00:00:00 2001 From: nidheesh-m-vakharia Date: Thu, 25 Jul 2024 18:45:22 -0700 Subject: [PATCH 03/19] fix:variable name change, Icons Change,Progress Bar Chnage --- src/components/admin/services/timer/Timer.jsx | 2 +- src/components/admin/services/timer/TimerEditMode.jsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/admin/services/timer/Timer.jsx b/src/components/admin/services/timer/Timer.jsx index 8e73b0292..5671618bd 100644 --- a/src/components/admin/services/timer/Timer.jsx +++ b/src/components/admin/services/timer/Timer.jsx @@ -161,7 +161,7 @@ export default function Timer({ name, onRemove }) { {!collapsed && ( <> {isEditMode ? ( - + ) : ( )} diff --git a/src/components/admin/services/timer/TimerEditMode.jsx b/src/components/admin/services/timer/TimerEditMode.jsx index fa0d5c1dc..3b59704c8 100644 --- a/src/components/admin/services/timer/TimerEditMode.jsx +++ b/src/components/admin/services/timer/TimerEditMode.jsx @@ -5,10 +5,10 @@ import { InputOTPSlot, } from "@/components/ui/input-otp"; -const TimerEditMode = ({ value, OnChange }) => ( +const TimerEditMode = ({ value, onChange }) => ( OnChange(value)} + onChange={(value) => onChange(value)} value={value} className="mt-4" > From 09d7b28f1dc5917d999d485759a53d81bf1b5471 Mon Sep 17 00:00:00 2001 From: nidheesh-m-vakharia Date: Sat, 27 Jul 2024 13:12:17 -0700 Subject: [PATCH 04/19] Change to Lucid Icons --- .../admin/services/timer/TimerControls.jsx | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/components/admin/services/timer/TimerControls.jsx b/src/components/admin/services/timer/TimerControls.jsx index b6147060d..2140612e4 100644 --- a/src/components/admin/services/timer/TimerControls.jsx +++ b/src/components/admin/services/timer/TimerControls.jsx @@ -1,12 +1,4 @@ -import { - FaPlay, - FaPause, - FaUndo, - FaTrashAlt, - FaPen, - FaCheck, - FaTimes, -} from "react-icons/fa"; +import { Play, Pause, Undo2, Trash2, Pen, Check, X } from "lucide-react"; import Tooltip from "./Tooltip"; const TimerControls = ({ @@ -28,37 +20,37 @@ const TimerControls = ({ <> {paused || isComplete ? ( - + ) : ( - + )} {!collapsed && ( <> - + - + )} - + ) : ( <> - {}} className={`text-2xl mx-1 ${invalid ? "text-gray-500" : ""}`} /> - + )} From 29b15525670322f0ed041332646c556694a90035 Mon Sep 17 00:00:00 2001 From: nidheesh-m-vakharia Date: Sat, 27 Jul 2024 13:35:13 -0700 Subject: [PATCH 05/19] fix: lucid icon added --- src/data/Navigation.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data/Navigation.js b/src/data/Navigation.js index 25f0c109e..6bc42e3ba 100644 --- a/src/data/Navigation.js +++ b/src/data/Navigation.js @@ -18,7 +18,7 @@ import { import { FaGear } from "react-icons/fa6"; import { AiOutlineQrcode } from "react-icons/ai"; import { SiHandshake } from "react-icons/si"; -import { RxLapTimer } from "react-icons/rx"; +import { Timer } from "lucide-react"; import { RiTeamFill } from "react-icons/ri"; import { IoIosPeople } from "react-icons/io"; @@ -130,7 +130,7 @@ export const TABS = { { name: "timer", link: "/admin/timer", - icon: , + icon: , }, ], }, From a47d0a9344fbbe1dfbb61698ed67b165f8662422 Mon Sep 17 00:00:00 2001 From: nidheesh-m-vakharia Date: Sun, 28 Jul 2024 00:28:56 -0700 Subject: [PATCH 06/19] fix:destructure --- src/components/admin/services/timer/Timer.jsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/admin/services/timer/Timer.jsx b/src/components/admin/services/timer/Timer.jsx index 5671618bd..b027b5509 100644 --- a/src/components/admin/services/timer/Timer.jsx +++ b/src/components/admin/services/timer/Timer.jsx @@ -93,24 +93,24 @@ export default function Timer({ name, onRemove }) { }; const saveChanges = () => { - const dateObject = numberToDate(editedValue); + const { hours, minutes, seconds } = numberToDate(editedValue); - if (dateObject.minutes > 59 || dateObject.seconds > 59) { + if (minutes > 59 || seconds > 59) { setInvalid(true); return; } setEditMode(false); - const total = - dateObject.hours * 3600 + dateObject.minutes * 60 + dateObject.seconds; + const total = hours * 3600 + minutes * 60 + seconds; setOriginal(total); setTotal(total); }; const inputOnChange = (value) => { if (value.length === 6) { - const dateObject = numberToDate(value); - if (dateObject.minutes > 59 || dateObject.seconds > 59) { + const { minutes, seconds } = numberToDate(value); + + if (minutes > 59 || seconds > 59) { setInvalid(true); } else { setInvalid(false); From 1e84ec198198e57f0187e1545108b5f27a5f3dbc Mon Sep 17 00:00:00 2001 From: nidheesh-m-vakharia Date: Sun, 28 Jul 2024 05:12:57 -0700 Subject: [PATCH 07/19] fix: arrow functions --- src/components/admin/services/timer/Timer.jsx | 8 ++++--- .../admin/services/timer/TimerPage.jsx | 24 ++++++++++--------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/components/admin/services/timer/Timer.jsx b/src/components/admin/services/timer/Timer.jsx index b027b5509..f6669e227 100644 --- a/src/components/admin/services/timer/Timer.jsx +++ b/src/components/admin/services/timer/Timer.jsx @@ -6,7 +6,7 @@ import TimerEditMode from "./TimerEditMode"; import { Progress } from "@/components/ui/progress"; import { ChevronDown, ChevronUp } from "lucide-react"; -export default function Timer({ name, onRemove }) { +const Timer = ({ name, onRemove }) => { const [paused, setPaused] = useState(true); const [total, setTotal] = useState(0); const [isComplete, setIsComplete] = useState(false); @@ -27,7 +27,7 @@ export default function Timer({ name, onRemove }) { useEffect(() => { resetTimer(); setEditedValue(""); - }, [isEditMode]); + }, [isEditMode, resetTimer]); useEffect(() => { const calculateTime = (seconds) => { @@ -174,4 +174,6 @@ export default function Timer({ name, onRemove }) { />
); -} +}; + +export default Timer; diff --git a/src/components/admin/services/timer/TimerPage.jsx b/src/components/admin/services/timer/TimerPage.jsx index 2278d3589..05e8c7d63 100644 --- a/src/components/admin/services/timer/TimerPage.jsx +++ b/src/components/admin/services/timer/TimerPage.jsx @@ -2,12 +2,12 @@ import { useState } from "react"; import Timer from "./Timer"; import { v4 as uuidv4 } from "uuid"; -export default function TimerPage() { - const [timerArray, setTimerArray] = useState([]); +const TimerPage = () => { + const [timers, setTimers] = useState([]); const addTimer = () => { - setTimerArray([ - ...timerArray, + setTimers([ + ...timers, { id: uuidv4(), }, @@ -15,11 +15,11 @@ export default function TimerPage() { }; const clearAll = () => { - setTimerArray([]); + setTimers([]); }; - const deleteTime = (id) => { - setTimerArray(timerArray.filter((timer) => timer.id !== id)); + const deleteTimer = (id) => { + setTimers(timers.filter((timer) => timer.id !== id)); }; return ( @@ -40,16 +40,18 @@ export default function TimerPage() {
- {timerArray.length === 0 ? ( + {timers.length === 0 ? (
No timers
) : ( - timerArray.map((timer) => ( - deleteTime(timer.id)} /> + timers.map((timer) => ( + deleteTimer(timer.id)} /> )) )}
); -} +}; + +export default TimerPage; From 883bb2a500b2cbfcf7f7a11615d383f44bccf44a Mon Sep 17 00:00:00 2001 From: nidheesh-m-vakharia Date: Sun, 28 Jul 2024 06:01:41 -0700 Subject: [PATCH 08/19] fix: array refactor, useEffect fix --- src/components/admin/services/timer/Timer.jsx | 2 +- src/components/admin/services/timer/TimerDisplay.jsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/admin/services/timer/Timer.jsx b/src/components/admin/services/timer/Timer.jsx index f6669e227..d90f5f561 100644 --- a/src/components/admin/services/timer/Timer.jsx +++ b/src/components/admin/services/timer/Timer.jsx @@ -27,7 +27,7 @@ const Timer = ({ name, onRemove }) => { useEffect(() => { resetTimer(); setEditedValue(""); - }, [isEditMode, resetTimer]); + }, [isEditMode]); useEffect(() => { const calculateTime = (seconds) => { diff --git a/src/components/admin/services/timer/TimerDisplay.jsx b/src/components/admin/services/timer/TimerDisplay.jsx index 376c9a3b3..53c9ee426 100644 --- a/src/components/admin/services/timer/TimerDisplay.jsx +++ b/src/components/admin/services/timer/TimerDisplay.jsx @@ -1,9 +1,9 @@ const TimerDisplay = ({ time }) => (
- {["Hours", "Minutes", "Seconds"].map((label, idx) => ( + {["Hours", "Minutes", "Seconds"].map((label) => (
- {time[idx === 0 ? "hours" : idx === 1 ? "minutes" : "seconds"]} + {time[label.toLowerCase()]}
{label}
From 57e35d70be7f9631c079f893a2462562cef18427 Mon Sep 17 00:00:00 2001 From: nidheesh-m-vakharia Date: Sun, 28 Jul 2024 09:35:19 -0700 Subject: [PATCH 09/19] fix: toaster implimented, tooltip z-index fix, [invalid, setInvalid] removed --- src/components/admin/services/timer/Timer.jsx | 36 +++++++------------ .../admin/services/timer/TimerControls.jsx | 6 +--- .../admin/services/timer/Tooltip.jsx | 2 +- 3 files changed, 14 insertions(+), 30 deletions(-) diff --git a/src/components/admin/services/timer/Timer.jsx b/src/components/admin/services/timer/Timer.jsx index d90f5f561..22e60e1d8 100644 --- a/src/components/admin/services/timer/Timer.jsx +++ b/src/components/admin/services/timer/Timer.jsx @@ -5,6 +5,7 @@ import TimerControls from "./TimerControls"; import TimerEditMode from "./TimerEditMode"; import { Progress } from "@/components/ui/progress"; import { ChevronDown, ChevronUp } from "lucide-react"; +import { toast } from "react-hot-toast"; const Timer = ({ name, onRemove }) => { const [paused, setPaused] = useState(true); @@ -13,7 +14,6 @@ const Timer = ({ name, onRemove }) => { const [isEditMode, setEditMode] = useState(false); const [original, setOriginal] = useState(0); const [editedValue, setEditedValue] = useState(""); - const [invalid, setInvalid] = useState(true); const [collapsed, setCollapsed] = useState(false); const timerRef = useRef(null); @@ -24,6 +24,12 @@ const Timer = ({ name, onRemove }) => { seconds: 0, }); + const resetTimer = () => { + setTotal(original); + setIsComplete(false); + setPaused(true); + }; + useEffect(() => { resetTimer(); setEditedValue(""); @@ -48,6 +54,7 @@ const Timer = ({ name, onRemove }) => { if (isComplete) { return; } + if (paused) { return; } @@ -71,16 +78,9 @@ const Timer = ({ name, onRemove }) => { } }; - const resetTimer = () => { - setTotal(original); - setIsComplete(false); - setPaused(true); - }; - const openEditMode = () => { setEditMode(true); setEditedValue(""); - setInvalid(true); }; const numberToDate = (num) => { @@ -93,12 +93,12 @@ const Timer = ({ name, onRemove }) => { }; const saveChanges = () => { - const { hours, minutes, seconds } = numberToDate(editedValue); - - if (minutes > 59 || seconds > 59) { - setInvalid(true); + if (editedValue.length !== 6) { + toast.error("Invalid time"); return; } + const { hours, minutes, seconds } = numberToDate(editedValue); + setEditMode(false); const total = hours * 3600 + minutes * 60 + seconds; @@ -107,17 +107,6 @@ const Timer = ({ name, onRemove }) => { }; const inputOnChange = (value) => { - if (value.length === 6) { - const { minutes, seconds } = numberToDate(value); - - if (minutes > 59 || seconds > 59) { - setInvalid(true); - } else { - setInvalid(false); - } - } else { - setInvalid(true); - } setEditedValue(value); }; @@ -152,7 +141,6 @@ const Timer = ({ name, onRemove }) => { onRemove={onRemove} saveChanges={saveChanges} discardChanges={discardChanges} - invalid={invalid} collapsed={collapsed} />
diff --git a/src/components/admin/services/timer/TimerControls.jsx b/src/components/admin/services/timer/TimerControls.jsx index 2140612e4..38d0e1ada 100644 --- a/src/components/admin/services/timer/TimerControls.jsx +++ b/src/components/admin/services/timer/TimerControls.jsx @@ -12,7 +12,6 @@ const TimerControls = ({ onRemove, saveChanges, discardChanges, - invalid, collapsed, }) => (
@@ -44,10 +43,7 @@ const TimerControls = ({ ) : ( <> - {}} - className={`text-2xl mx-1 ${invalid ? "text-gray-500" : ""}`} - /> + diff --git a/src/components/admin/services/timer/Tooltip.jsx b/src/components/admin/services/timer/Tooltip.jsx index 4c43cc08c..7a5c7ae30 100644 --- a/src/components/admin/services/timer/Tooltip.jsx +++ b/src/components/admin/services/timer/Tooltip.jsx @@ -1,6 +1,6 @@ const Tooltip = ({ children, text }) => { return ( -
+
{children}
{text} From 2e0e6bad5c7a8f94a9e665212d10bc9a52052000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jasmine=20Tr=C3=ACnh?= <168297703+minnieland@users.noreply.github.com> Date: Wed, 24 Jul 2024 17:09:43 -0700 Subject: [PATCH 10/19] add prettier that helps with ordering of code style --- cypress/component/Checkbox.cy.jsx | 6 +- cypress/component/Input.cy.jsx | 2 +- cypress/component/Radio.cy.jsx | 8 +- cypress/component/admin/Button.cy.jsx | 10 +-- cypress/component/admin/Dropdown.cy.jsx | 4 +- cypress/component/admin/Event.cy.jsx | 4 +- cypress/component/admin/Input.cy.jsx | 2 +- cypress/component/admin/Modal.cy.jsx | 8 +- cypress/component/admin/Tag.cy.jsx | 14 +-- cypress/component/admin/Title.cy.jsx | 4 +- cypress/component/admin/Upload.cy.jsx | 4 +- cypress/component/form/Button.cy.jsx | 2 +- cypress/component/form/Confirmation.cy.jsx | 2 +- cypress/component/form/Status.cy.jsx | 2 +- cypress/component/user/Hackpack.cy.jsx | 6 +- cypress/support/commands.js | 4 +- cypress/support/component-index.html | 2 +- package-lock.json | 87 +++++++++++++++++-- package.json | 3 +- src/app/admin/[type]/page.js | 2 +- src/app/api/checkin/route.js | 8 +- src/app/api/contacts/route.js | 6 +- src/app/api/dashboard/[type]/route.js | 38 ++++---- src/app/api/dashboard/feedback/route.js | 36 ++++---- src/app/api/dashboard/teams/route.js | 30 +++---- src/app/api/judging/route.js | 24 ++--- src/app/api/members/route.js | 8 +- src/app/api/participant/route.js | 4 +- src/app/api/settings/route.js | 8 +- src/app/api/statistics/route.js | 4 +- src/app/api/team/route.js | 16 ++-- src/app/engineering/blog/[type]/page.js | 2 +- src/app/form/[type]/page.js | 2 +- src/components/ProtectedPage.jsx | 6 +- src/components/Select.jsx | 4 +- .../admin/dashboards/dashboard/Filter.jsx | 2 +- .../admin/dashboards/dashboard/Table.jsx | 2 +- .../admin/dashboards/dashboard/Toolbar.jsx | 6 +- src/components/admin/services/Dropdown.jsx | 2 +- .../services/calendar/CalendarWrapper.jsx | 2 +- .../admin/services/calendar/Events.jsx | 4 +- .../admin/services/calendar/Toolbar.jsx | 2 +- .../admin/services/checkin/CheckIn.jsx | 2 +- .../admin/services/judging/Toolbar.jsx | 8 +- src/components/form/form/Form.jsx | 2 +- src/components/form/form/Questions.jsx | 6 +- src/components/form/form/Upload.jsx | 2 +- src/components/live/schedule/Events.jsx | 2 +- src/components/ui/alert-dialog.jsx | 12 +-- src/components/ui/button.jsx | 4 +- src/components/ui/card.jsx | 4 +- src/components/ui/chart.jsx | 28 +++--- src/components/ui/checkbox.jsx | 2 +- src/components/ui/input.jsx | 2 +- src/components/ui/label.jsx | 2 +- src/components/ui/tabs.jsx | 6 +- src/components/user/Countdown.jsx | 2 +- src/components/user/User.jsx | 2 +- src/components/user/team/Details.jsx | 2 +- src/engineering/Schedule.mdx | 4 +- src/engineering/nextauth.mdx | 2 +- src/engineering/team.mdx | 2 +- src/engineering/toast.mdx | 2 +- src/utils/auth.ts | 2 +- 64 files changed, 284 insertions(+), 208 deletions(-) diff --git a/cypress/component/Checkbox.cy.jsx b/cypress/component/Checkbox.cy.jsx index 98dce7351..69a75d613 100644 --- a/cypress/component/Checkbox.cy.jsx +++ b/cypress/component/Checkbox.cy.jsx @@ -17,7 +17,7 @@ describe("Checkbox", () => { cy.get('[data-cy="checkbox-bg"]').should( "have.class", - "bg-hackathon-gray-100" + "bg-hackathon-gray-100", ); }); @@ -36,7 +36,7 @@ describe("Checkbox", () => { cy.get('[data-cy="checkbox-bg"]').should( "have.class", - "bg-hackathon-blue-100" + "bg-hackathon-blue-100", ); }); @@ -73,7 +73,7 @@ describe("Checkbox", () => { cy.get('[data-cy="checkbox-bg"]').click(); cy.get('[data-cy="checkbox-bg"]').should( "have.class", - "bg-hackathon-blue-100" + "bg-hackathon-blue-100", ); }); }); diff --git a/cypress/component/Input.cy.jsx b/cypress/component/Input.cy.jsx index ab5038710..d1b14f705 100644 --- a/cypress/component/Input.cy.jsx +++ b/cypress/component/Input.cy.jsx @@ -21,7 +21,7 @@ describe("Input", () => { cy.get('[data-cy="first-input"]').should( "have.attr", "placeholder", - "John" + "John", ); }); diff --git a/cypress/component/Radio.cy.jsx b/cypress/component/Radio.cy.jsx index a3b9bf06d..830f725f4 100644 --- a/cypress/component/Radio.cy.jsx +++ b/cypress/component/Radio.cy.jsx @@ -66,23 +66,23 @@ describe("Radio", () => { cy.get("[data-cy=radio-button-female]").should( "have.class", - "bg-hackathon-green-300" + "bg-hackathon-green-300", ); cy.get("[data-cy=radio-button-male]").should( "have.class", - "bg-transparent" + "bg-transparent", ); cy.get("[data-cy=radio-button-male]").click(); cy.get("[data-cy=radio-button-male]").should( "have.class", - "bg-hackathon-green-300" + "bg-hackathon-green-300", ); cy.get("[data-cy=radio-button-female]").should( "have.class", - "bg-transparent" + "bg-transparent", ); }); diff --git a/cypress/component/admin/Button.cy.jsx b/cypress/component/admin/Button.cy.jsx index 28e911f30..283eb7d9b 100644 --- a/cypress/component/admin/Button.cy.jsx +++ b/cypress/component/admin/Button.cy.jsx @@ -9,14 +9,14 @@ describe("Button", () => { const size = "md"; cy.mount( -
, ); }; diff --git a/src/utils/auth.ts b/src/utils/auth.ts index cab3bf9d5..b5991b047 100644 --- a/src/utils/auth.ts +++ b/src/utils/auth.ts @@ -52,7 +52,7 @@ export const authenticate = async (restrictions: Restrictions = {}) => { } const authorized = Object.entries(restrictions).some(([key, value]) => - value.includes(session?.user?.roles[key]) + value.includes(session?.user?.roles[key]), ); if (!authorized && Object.keys(restrictions).length > 0) { From 6dc80a1874d5c8ff34de4942667af9ed63997c41 Mon Sep 17 00:00:00 2001 From: Howardwheeler Date: Thu, 25 Jul 2024 15:19:15 -0700 Subject: [PATCH 11/19] Made Tab component test --- cypress/component/admin/Tab.cy.jsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 cypress/component/admin/Tab.cy.jsx diff --git a/cypress/component/admin/Tab.cy.jsx b/cypress/component/admin/Tab.cy.jsx new file mode 100644 index 000000000..975768876 --- /dev/null +++ b/cypress/component/admin/Tab.cy.jsx @@ -0,0 +1,12 @@ +import Tab from "@/components/admin/services/statistics/Tab.jsx"; + +describe("Tab", () => { + it("Tab-box", () => { + const title = "hackathon"; + const value = "10"; + + cy.mount(); + cy.get('[data-cy="hackathon-tab"]').should("have.text", title); + cy.get('[data-cy="10-value"]').should("have.text", value); + }); +}); From 6ccbf92f2f13b39b165f405bda8d75afd240741d Mon Sep 17 00:00:00 2001 From: shahdivyank Date: Thu, 25 Jul 2024 20:17:09 -0700 Subject: [PATCH 12/19] fix tests --- cypress/component/user/BulletPoints.cy.jsx | 4 ++-- cypress/component/user/Hackpack.cy.jsx | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cypress/component/user/BulletPoints.cy.jsx b/cypress/component/user/BulletPoints.cy.jsx index cbbd6d154..4b98e0856 100644 --- a/cypress/component/user/BulletPoints.cy.jsx +++ b/cypress/component/user/BulletPoints.cy.jsx @@ -2,8 +2,8 @@ import BulletPoints from "@/components/user/BulletPoints"; describe("BulletPoints", () => { it("BulletPoints", () => { - const classes = "flex flex-col items-center justify-center mt-2"; - const listClass = "list-disc w-10/12"; + const classes = "mt-2 flex flex-col items-center justify-center"; + const listClass = "w-10/12 list-disc"; const list = ["first item", "second item"]; cy.mount(); diff --git a/cypress/component/user/Hackpack.cy.jsx b/cypress/component/user/Hackpack.cy.jsx index aba3bbf0b..39a9cfc11 100644 --- a/cypress/component/user/Hackpack.cy.jsx +++ b/cypress/component/user/Hackpack.cy.jsx @@ -18,7 +18,7 @@ describe("HackPacks", () => { cy.get('[data-cy="hackpack-link"]') .should( "have.class", - "w-full bg-gray-100 rounded-xl p-4 hover:border-gray-300 border-gray-100 border-2 duration-300", + "w-full rounded-xl border-2 border-gray-100 bg-gray-100 p-4 duration-300 hover:border-gray-300", ) .should("have.attr", "href", link) .should("have.attr", "target", "_black"); @@ -37,15 +37,15 @@ describe("HackPacks", () => { techs.forEach((tech, index) => { cy.get('[data-cy="hackpack-techs"] [data-cy="hackpack-tech"]') .eq(index) - .should("contain.text", tech) + .contains(tech) .should( "have.class", - "text-gray-400 rounded-full flex items-center px-1", + "flex items-center rounded-full px-1 text-gray-400", ); cy.get('[data-cy="hackpack-tech"] [data-cy="hackpack-icon"]') .eq(index) - .should("have.class", "text-hackathon-blue-100 mr-1"); + .should("have.class", "mr-1 text-hackathon-blue-100"); }); }); }); From e01e1da46360d4654b1a9714c5bfbcafd124c91d Mon Sep 17 00:00:00 2001 From: fardinzam Date: Thu, 25 Jul 2024 17:53:18 -0700 Subject: [PATCH 13/19] removed cursor animation on hover --- src/components/user/BulletList.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/user/BulletList.jsx b/src/components/user/BulletList.jsx index 4e545d5a6..e41c35cc4 100644 --- a/src/components/user/BulletList.jsx +++ b/src/components/user/BulletList.jsx @@ -1,7 +1,7 @@ const BulletList = ({ text, children }) => { return (
-
+
{text}
{children}
From 86ff42507115702126e0ec68c226e4b6708c0df2 Mon Sep 17 00:00:00 2001 From: nidheesh-m-vakharia Date: Sun, 28 Jul 2024 10:29:17 -0700 Subject: [PATCH 14/19] fix: formatting issues --- src/components/admin/services/timer/Timer.jsx | 8 ++++---- .../admin/services/timer/TimerControls.jsx | 14 +++++++------- .../admin/services/timer/TimerDisplay.jsx | 4 ++-- src/components/admin/services/timer/TimerPage.jsx | 12 ++++++------ .../admin/services/timer/TimerStatus.jsx | 6 +++--- src/components/admin/services/timer/Tooltip.jsx | 4 ++-- src/components/ui/input-otp.jsx | 6 +++--- src/components/ui/progress.jsx | 2 +- 8 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/components/admin/services/timer/Timer.jsx b/src/components/admin/services/timer/Timer.jsx index 22e60e1d8..e1b8cd08b 100644 --- a/src/components/admin/services/timer/Timer.jsx +++ b/src/components/admin/services/timer/Timer.jsx @@ -119,13 +119,13 @@ const Timer = ({ name, onRemove }) => { }; return ( -
-
+
+
@@ -158,7 +158,7 @@ const Timer = ({ name, onRemove }) => { )}
); diff --git a/src/components/admin/services/timer/TimerControls.jsx b/src/components/admin/services/timer/TimerControls.jsx index 38d0e1ada..aa5208d1c 100644 --- a/src/components/admin/services/timer/TimerControls.jsx +++ b/src/components/admin/services/timer/TimerControls.jsx @@ -19,34 +19,34 @@ const TimerControls = ({ <> {paused || isComplete ? ( - + ) : ( - + )} {!collapsed && ( <> - + - + )} - + ) : ( <> - + - + )} diff --git a/src/components/admin/services/timer/TimerDisplay.jsx b/src/components/admin/services/timer/TimerDisplay.jsx index 53c9ee426..f1c56bf84 100644 --- a/src/components/admin/services/timer/TimerDisplay.jsx +++ b/src/components/admin/services/timer/TimerDisplay.jsx @@ -1,8 +1,8 @@ const TimerDisplay = ({ time }) => ( -
+
{["Hours", "Minutes", "Seconds"].map((label) => (
-
+
{time[label.toLowerCase()]}
{label}
diff --git a/src/components/admin/services/timer/TimerPage.jsx b/src/components/admin/services/timer/TimerPage.jsx index 05e8c7d63..3429586d6 100644 --- a/src/components/admin/services/timer/TimerPage.jsx +++ b/src/components/admin/services/timer/TimerPage.jsx @@ -24,24 +24,24 @@ const TimerPage = () => { return (
-
-

Timer

+
+

Timer

-
+
{timers.length === 0 ? ( -
+
No timers
) : ( diff --git a/src/components/admin/services/timer/TimerStatus.jsx b/src/components/admin/services/timer/TimerStatus.jsx index 82bf0182f..3910c1eaa 100644 --- a/src/components/admin/services/timer/TimerStatus.jsx +++ b/src/components/admin/services/timer/TimerStatus.jsx @@ -1,20 +1,20 @@ const TimerStatus = ({ isComplete, paused }) => { if (isComplete) { return ( -
+
Completed
); } if (paused) { return ( -
+
Not Running
); } return ( -
+
Running
); diff --git a/src/components/admin/services/timer/Tooltip.jsx b/src/components/admin/services/timer/Tooltip.jsx index 7a5c7ae30..5bdf48d2c 100644 --- a/src/components/admin/services/timer/Tooltip.jsx +++ b/src/components/admin/services/timer/Tooltip.jsx @@ -1,8 +1,8 @@ const Tooltip = ({ children, text }) => { return ( -
+
{children} -
+
{text}
diff --git a/src/components/ui/input-otp.jsx b/src/components/ui/input-otp.jsx index adf3249af..fd37f4068 100644 --- a/src/components/ui/input-otp.jsx +++ b/src/components/ui/input-otp.jsx @@ -12,12 +12,12 @@ const InputOTP = React.forwardRef( ref={ref} containerClassName={cn( "flex items-center gap-2 has-[:disabled]:opacity-50", - containerClassName + containerClassName, )} className={cn("disabled:cursor-not-allowed", className)} {...props} /> - ) + ), ); InputOTP.displayName = "InputOTP"; @@ -37,7 +37,7 @@ const InputOTPSlot = React.forwardRef(({ index, className, ...props }, ref) => { "relative flex h-20 w-20 items-center justify-center border-y border-r border-slate-200 text-2xl transition-all first:rounded-l-md first:border-l last:rounded-r-md dark:border-slate-800", isActive && "z-10 ring-2 ring-slate-950 ring-offset-white dark:ring-slate-300 dark:ring-offset-slate-950", - className + className, )} {...props} > diff --git a/src/components/ui/progress.jsx b/src/components/ui/progress.jsx index d43a1ddf0..769221e68 100644 --- a/src/components/ui/progress.jsx +++ b/src/components/ui/progress.jsx @@ -10,7 +10,7 @@ const Progress = React.forwardRef(({ className, value, ...props }, ref) => ( ref={ref} className={cn( "relative h-4 w-full overflow-hidden rounded-full bg-slate-100 dark:bg-slate-800", - className + className, )} {...props} > From 49a7e102ea6d558f2c267dde106bdae1e78aef34 Mon Sep 17 00:00:00 2001 From: nidheesh-m-vakharia Date: Sun, 28 Jul 2024 11:13:49 -0700 Subject: [PATCH 15/19] fix: filenames, TimerPage to Timer --- src/app/admin/[type]/page.js | 4 +- src/components/admin/services/timer/Clock.jsx | 167 +++++++++++++++ .../timer/{TimerControls.jsx => Controls.jsx} | 4 +- .../timer/{TimerDisplay.jsx => Display.jsx} | 4 +- .../timer/{TimerEditMode.jsx => EditMode.jsx} | 4 +- .../timer/{TimerStatus.jsx => Status.jsx} | 4 +- src/components/admin/services/timer/Timer.jsx | 192 ++++-------------- .../admin/services/timer/TimerPage.jsx | 57 ------ 8 files changed, 218 insertions(+), 218 deletions(-) create mode 100644 src/components/admin/services/timer/Clock.jsx rename src/components/admin/services/timer/{TimerControls.jsx => Controls.jsx} (96%) rename src/components/admin/services/timer/{TimerDisplay.jsx => Display.jsx} (85%) rename src/components/admin/services/timer/{TimerEditMode.jsx => EditMode.jsx} (88%) rename src/components/admin/services/timer/{TimerStatus.jsx => Status.jsx} (89%) delete mode 100644 src/components/admin/services/timer/TimerPage.jsx diff --git a/src/app/admin/[type]/page.js b/src/app/admin/[type]/page.js index ab8ee38fa..14256428c 100644 --- a/src/app/admin/[type]/page.js +++ b/src/app/admin/[type]/page.js @@ -19,7 +19,7 @@ import Volunteers from "@/components/admin/dashboards/Volunteers"; import Leads from "@/components/admin/dashboards/Leads"; import Fault from "@/utils/error"; import Settings from "@/components/admin/services/settings/Settings"; -import TimerPage from "@/components/admin/services/timer/TimerPage"; +import Timer from "@/components/admin/services/timer/Timer"; const Page = ({ params, searchParams }) => { const components = { @@ -41,7 +41,7 @@ const Page = ({ params, searchParams }) => { teams: , volunteers: , leads: , - timer: , + timer: , }; const capitalizeFirstLetter = (word) => { diff --git a/src/components/admin/services/timer/Clock.jsx b/src/components/admin/services/timer/Clock.jsx new file mode 100644 index 000000000..edbf80dfe --- /dev/null +++ b/src/components/admin/services/timer/Clock.jsx @@ -0,0 +1,167 @@ +import { useState, useEffect, useRef } from "react"; +import Display from "./Display"; +import Status from "./Status"; +import Controls from "./Controls"; +import EditMode from "./EditMode"; +import { Progress } from "@/components/ui/progress"; +import { ChevronDown, ChevronUp } from "lucide-react"; +import { toast } from "react-hot-toast"; + +const Timer = ({ name, onRemove }) => { + const [paused, setPaused] = useState(true); + const [total, setTotal] = useState(0); + const [isComplete, setIsComplete] = useState(false); + const [isEditMode, setEditMode] = useState(false); + const [original, setOriginal] = useState(0); + const [editedValue, setEditedValue] = useState(""); + const [collapsed, setCollapsed] = useState(false); + + const timerRef = useRef(null); + + const [time, setTime] = useState({ + hours: 0, + minutes: 0, + seconds: 0, + }); + + const resetTimer = () => { + setTotal(original); + setIsComplete(false); + setPaused(true); + }; + + useEffect(() => { + resetTimer(); + setEditedValue(""); + }, [isEditMode]); + + useEffect(() => { + const calculateTime = (seconds) => { + return { + hours: Math.floor((seconds % 86400) / 3600), + minutes: Math.floor((seconds % 3600) / 60), + seconds: seconds % 60, + }; + }; + + setTime(calculateTime(total)); + + if (total === 0) { + setPaused(true); + setIsComplete(true); + return; + } + if (isComplete) { + return; + } + + if (paused) { + return; + } + + timerRef.current = setTimeout(() => { + setTotal((prevSeconds) => prevSeconds - 1); + }, 1000); + + return () => clearTimeout(timerRef.current); + }, [paused, isComplete, total]); + + const pauseTimer = () => { + setPaused(true); + }; + + const resumeTimer = () => { + if (isComplete) { + setPaused(true); + } else { + setPaused(false); + } + }; + + const openEditMode = () => { + setEditMode(true); + setEditedValue(""); + }; + + const numberToDate = (num) => { + const dateString = num.toString().padEnd(6, "0"); + return { + hours: parseInt(dateString.substr(0, 2)), + minutes: parseInt(dateString.substr(2, 2)), + seconds: parseInt(dateString.substr(4, 2)), + }; + }; + + const saveChanges = () => { + if (editedValue.length !== 6) { + toast.error("Invalid time"); + return; + } + const { hours, minutes, seconds } = numberToDate(editedValue); + + setEditMode(false); + + const total = hours * 3600 + minutes * 60 + seconds; + setOriginal(total); + setTotal(total); + }; + + const inputOnChange = (value) => { + setEditedValue(value); + }; + + const discardChanges = () => { + setEditMode(false); + }; + + const toggleCollapse = () => { + setCollapsed((prev) => !prev); + }; + + return ( +
+
+ + +
+ +
+
+ + {!collapsed && ( + <> + {isEditMode ? ( + + ) : ( + + )} + + + )} + +
+ ); +}; + +export default Timer; diff --git a/src/components/admin/services/timer/TimerControls.jsx b/src/components/admin/services/timer/Controls.jsx similarity index 96% rename from src/components/admin/services/timer/TimerControls.jsx rename to src/components/admin/services/timer/Controls.jsx index aa5208d1c..29f764d75 100644 --- a/src/components/admin/services/timer/TimerControls.jsx +++ b/src/components/admin/services/timer/Controls.jsx @@ -1,7 +1,7 @@ import { Play, Pause, Undo2, Trash2, Pen, Check, X } from "lucide-react"; import Tooltip from "./Tooltip"; -const TimerControls = ({ +const Controls = ({ isEditMode, paused, isComplete, @@ -53,4 +53,4 @@ const TimerControls = ({
); -export default TimerControls; +export default Controls; diff --git a/src/components/admin/services/timer/TimerDisplay.jsx b/src/components/admin/services/timer/Display.jsx similarity index 85% rename from src/components/admin/services/timer/TimerDisplay.jsx rename to src/components/admin/services/timer/Display.jsx index f1c56bf84..edb4a9a5e 100644 --- a/src/components/admin/services/timer/TimerDisplay.jsx +++ b/src/components/admin/services/timer/Display.jsx @@ -1,4 +1,4 @@ -const TimerDisplay = ({ time }) => ( +const Display = ({ time }) => (
{["Hours", "Minutes", "Seconds"].map((label) => (
@@ -11,4 +11,4 @@ const TimerDisplay = ({ time }) => (
); -export default TimerDisplay; +export default Display; diff --git a/src/components/admin/services/timer/TimerEditMode.jsx b/src/components/admin/services/timer/EditMode.jsx similarity index 88% rename from src/components/admin/services/timer/TimerEditMode.jsx rename to src/components/admin/services/timer/EditMode.jsx index 3b59704c8..66e616957 100644 --- a/src/components/admin/services/timer/TimerEditMode.jsx +++ b/src/components/admin/services/timer/EditMode.jsx @@ -5,7 +5,7 @@ import { InputOTPSlot, } from "@/components/ui/input-otp"; -const TimerEditMode = ({ value, onChange }) => ( +const EditMode = ({ value, onChange }) => ( onChange(value)} @@ -28,4 +28,4 @@ const TimerEditMode = ({ value, onChange }) => ( ); -export default TimerEditMode; +export default EditMode; diff --git a/src/components/admin/services/timer/TimerStatus.jsx b/src/components/admin/services/timer/Status.jsx similarity index 89% rename from src/components/admin/services/timer/TimerStatus.jsx rename to src/components/admin/services/timer/Status.jsx index 3910c1eaa..ca9c5188b 100644 --- a/src/components/admin/services/timer/TimerStatus.jsx +++ b/src/components/admin/services/timer/Status.jsx @@ -1,4 +1,4 @@ -const TimerStatus = ({ isComplete, paused }) => { +const Status = ({ isComplete, paused }) => { if (isComplete) { return (
@@ -20,4 +20,4 @@ const TimerStatus = ({ isComplete, paused }) => { ); }; -export default TimerStatus; +export default Status; diff --git a/src/components/admin/services/timer/Timer.jsx b/src/components/admin/services/timer/Timer.jsx index e1b8cd08b..967492537 100644 --- a/src/components/admin/services/timer/Timer.jsx +++ b/src/components/admin/services/timer/Timer.jsx @@ -1,165 +1,55 @@ -import { useState, useEffect, useRef } from "react"; -import TimerDisplay from "./TimerDisplay"; -import TimerStatus from "./TimerStatus"; -import TimerControls from "./TimerControls"; -import TimerEditMode from "./TimerEditMode"; -import { Progress } from "@/components/ui/progress"; -import { ChevronDown, ChevronUp } from "lucide-react"; -import { toast } from "react-hot-toast"; +import { useState } from "react"; +import Clock from "./Clock"; +import { v4 as uuidv4 } from "uuid"; -const Timer = ({ name, onRemove }) => { - const [paused, setPaused] = useState(true); - const [total, setTotal] = useState(0); - const [isComplete, setIsComplete] = useState(false); - const [isEditMode, setEditMode] = useState(false); - const [original, setOriginal] = useState(0); - const [editedValue, setEditedValue] = useState(""); - const [collapsed, setCollapsed] = useState(false); +const Timer = () => { + const [timers, setTimers] = useState([]); - const timerRef = useRef(null); - - const [time, setTime] = useState({ - hours: 0, - minutes: 0, - seconds: 0, - }); - - const resetTimer = () => { - setTotal(original); - setIsComplete(false); - setPaused(true); - }; - - useEffect(() => { - resetTimer(); - setEditedValue(""); - }, [isEditMode]); - - useEffect(() => { - const calculateTime = (seconds) => { - return { - hours: Math.floor((seconds % 86400) / 3600), - minutes: Math.floor((seconds % 3600) / 60), - seconds: seconds % 60, - }; - }; - - setTime(calculateTime(total)); - - if (total === 0) { - setPaused(true); - setIsComplete(true); - return; - } - if (isComplete) { - return; - } - - if (paused) { - return; - } - - timerRef.current = setTimeout(() => { - setTotal((prevSeconds) => prevSeconds - 1); - }, 1000); - - return () => clearTimeout(timerRef.current); - }, [paused, isComplete, total]); - - const pauseTimer = () => { - setPaused(true); - }; - - const resumeTimer = () => { - if (isComplete) { - setPaused(true); - } else { - setPaused(false); - } + const addTimer = () => { + setTimers([ + ...timers, + { + id: uuidv4(), + }, + ]); }; - const openEditMode = () => { - setEditMode(true); - setEditedValue(""); + const clearAll = () => { + setTimers([]); }; - const numberToDate = (num) => { - const dateString = num.toString().padEnd(6, "0"); - return { - hours: parseInt(dateString.substr(0, 2)), - minutes: parseInt(dateString.substr(2, 2)), - seconds: parseInt(dateString.substr(4, 2)), - }; - }; - - const saveChanges = () => { - if (editedValue.length !== 6) { - toast.error("Invalid time"); - return; - } - const { hours, minutes, seconds } = numberToDate(editedValue); - - setEditMode(false); - - const total = hours * 3600 + minutes * 60 + seconds; - setOriginal(total); - setTotal(total); - }; - - const inputOnChange = (value) => { - setEditedValue(value); - }; - - const discardChanges = () => { - setEditMode(false); - }; - - const toggleCollapse = () => { - setCollapsed((prev) => !prev); + const deleteTimer = (id) => { + setTimers(timers.filter((timer) => timer.id !== id)); }; return ( -
-
- + - -
- -
- - {!collapsed && ( - <> - {isEditMode ? ( - - ) : ( - - )} - - - )} - +
+ {timers.length === 0 ? ( +
+ No timers +
+ ) : ( + timers.map((timer) => ( + deleteTimer(timer.id)} /> + )) + )} +
); }; diff --git a/src/components/admin/services/timer/TimerPage.jsx b/src/components/admin/services/timer/TimerPage.jsx deleted file mode 100644 index 3429586d6..000000000 --- a/src/components/admin/services/timer/TimerPage.jsx +++ /dev/null @@ -1,57 +0,0 @@ -import { useState } from "react"; -import Timer from "./Timer"; -import { v4 as uuidv4 } from "uuid"; - -const TimerPage = () => { - const [timers, setTimers] = useState([]); - - const addTimer = () => { - setTimers([ - ...timers, - { - id: uuidv4(), - }, - ]); - }; - - const clearAll = () => { - setTimers([]); - }; - - const deleteTimer = (id) => { - setTimers(timers.filter((timer) => timer.id !== id)); - }; - - return ( -
-
-

Timer

- - -
-
- {timers.length === 0 ? ( -
- No timers -
- ) : ( - timers.map((timer) => ( - deleteTimer(timer.id)} /> - )) - )} -
-
- ); -}; - -export default TimerPage; From dcd6de39d6603cb1a6d409ea15c38cca116a5b22 Mon Sep 17 00:00:00 2001 From: shahdivyank Date: Mon, 5 Aug 2024 02:11:03 -0700 Subject: [PATCH 16/19] cleanup --- package-lock.json | 120 ++++++++++ src/components/admin/services/timer/Clock.jsx | 222 +++++++----------- .../admin/services/timer/Controls.jsx | 72 ++---- .../admin/services/timer/Display.jsx | 14 -- .../admin/services/timer/EditMode.jsx | 31 --- .../admin/services/timer/Status.jsx | 23 -- .../admin/services/timer/Tooltip.jsx | 12 - 7 files changed, 223 insertions(+), 271 deletions(-) delete mode 100644 src/components/admin/services/timer/Display.jsx delete mode 100644 src/components/admin/services/timer/EditMode.jsx delete mode 100644 src/components/admin/services/timer/Status.jsx delete mode 100644 src/components/admin/services/timer/Tooltip.jsx diff --git a/package-lock.json b/package-lock.json index c6eefe907..7ade755d8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1358,6 +1358,126 @@ "node": ">= 10" } }, + "node_modules/@next/swc-darwin-x64": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.1.4.tgz", + "integrity": "sha512-b0Xo1ELj3u7IkZWAKcJPJEhBop117U78l70nfoQGo4xUSvv0PJSTaV4U9xQBLvZlnjsYkc8RwQN1HoH/oQmLlQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.1.4.tgz", + "integrity": "sha512-457G0hcLrdYA/u1O2XkRMsDKId5VKe3uKPvrKVOyuARa6nXrdhJOOYU9hkKKyQTMru1B8qEP78IAhf/1XnVqKA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.1.4.tgz", + "integrity": "sha512-l/kMG+z6MB+fKA9KdtyprkTQ1ihlJcBh66cf0HvqGP+rXBbOXX0dpJatjZbHeunvEHoBBS69GYQG5ry78JMy3g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.1.4.tgz", + "integrity": "sha512-BapIFZ3ZRnvQ1uWbmqEGJuPT9cgLwvKtxhK/L2t4QYO7l+/DxXuIGjvp1x8rvfa/x1FFSsipERZK70pewbtJtw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.1.4.tgz", + "integrity": "sha512-mqVxTwk4XuBl49qn2A5UmzFImoL1iLm0KQQwtdRJRKl21ylQwwGCxJtIYo2rbfkZHoSKlh/YgztY0qH3wG1xIg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.1.4.tgz", + "integrity": "sha512-xzxF4ErcumXjO2Pvg/wVGrtr9QQJLk3IyQX1ddAC/fi6/5jZCZ9xpuL9Tzc4KPWMFq8GGWFVDMshZOdHGdkvag==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.1.4.tgz", + "integrity": "sha512-WZiz8OdbkpRw6/IU/lredZWKKZopUMhcI2F+XiMAcPja0uZYdMTZQRoQ0WZcvinn9xZAidimE7tN9W5v9Yyfyw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.1.4.tgz", + "integrity": "sha512-4Rto21sPfw555sZ/XNLqfxDUNeLhNYGO2dlPqsnuCg8N8a2a9u1ltqBOPQ4vj1Gf7eJC0W2hHG2eYUHuiXgY2w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", diff --git a/src/components/admin/services/timer/Clock.jsx b/src/components/admin/services/timer/Clock.jsx index edbf80dfe..5e32d425d 100644 --- a/src/components/admin/services/timer/Clock.jsx +++ b/src/components/admin/services/timer/Clock.jsx @@ -1,163 +1,109 @@ -import { useState, useEffect, useRef } from "react"; -import Display from "./Display"; -import Status from "./Status"; +import { useState, useEffect } from "react"; import Controls from "./Controls"; -import EditMode from "./EditMode"; import { Progress } from "@/components/ui/progress"; -import { ChevronDown, ChevronUp } from "lucide-react"; -import { toast } from "react-hot-toast"; - -const Timer = ({ name, onRemove }) => { - const [paused, setPaused] = useState(true); - const [total, setTotal] = useState(0); - const [isComplete, setIsComplete] = useState(false); - const [isEditMode, setEditMode] = useState(false); +import { Pause, Play } from "lucide-react"; +import { + InputOTP, + InputOTPGroup, + InputOTPSlot, +} from "@/components/ui/input-otp"; + +const Timer = ({ onRemove }) => { + const [edit, setEdit] = useState(false); + const [play, setPlay] = useState(false); + const [total, setTotal] = useState(60000); const [original, setOriginal] = useState(0); - const [editedValue, setEditedValue] = useState(""); - const [collapsed, setCollapsed] = useState(false); - - const timerRef = useRef(null); - const [time, setTime] = useState({ - hours: 0, - minutes: 0, - seconds: 0, + hours: "00", + minutes: "01", + seconds: "00", }); - const resetTimer = () => { - setTotal(original); - setIsComplete(false); - setPaused(true); - }; - - useEffect(() => { - resetTimer(); - setEditedValue(""); - }, [isEditMode]); - - useEffect(() => { - const calculateTime = (seconds) => { - return { - hours: Math.floor((seconds % 86400) / 3600), - minutes: Math.floor((seconds % 3600) / 60), - seconds: seconds % 60, - }; - }; - - setTime(calculateTime(total)); - - if (total === 0) { - setPaused(true); - setIsComplete(true); - return; - } - if (isComplete) { - return; - } - - if (paused) { - return; - } - - timerRef.current = setTimeout(() => { - setTotal((prevSeconds) => prevSeconds - 1); - }, 1000); - - return () => clearTimeout(timerRef.current); - }, [paused, isComplete, total]); - - const pauseTimer = () => { - setPaused(true); - }; - - const resumeTimer = () => { - if (isComplete) { - setPaused(true); - } else { - setPaused(false); - } - }; - - const openEditMode = () => { - setEditMode(true); - setEditedValue(""); - }; + const onChange = (value) => { + if (!edit) return; - const numberToDate = (num) => { - const dateString = num.toString().padEnd(6, "0"); - return { - hours: parseInt(dateString.substr(0, 2)), - minutes: parseInt(dateString.substr(2, 2)), - seconds: parseInt(dateString.substr(4, 2)), - }; - }; - - const saveChanges = () => { - if (editedValue.length !== 6) { - toast.error("Invalid time"); - return; - } - const { hours, minutes, seconds } = numberToDate(editedValue); + const [hours, minutes, seconds] = value.match(/.{2}/g); - setEditMode(false); + setTime({ + hours, + minutes, + seconds, + }); - const total = hours * 3600 + minutes * 60 + seconds; - setOriginal(total); - setTotal(total); + setTotal( + parseInt(hours) * (1000 * 60 * 60) + + parseInt(minutes) * (1000 * 60) + + parseInt(seconds) * 1000, + ); }; - const inputOnChange = (value) => { - setEditedValue(value); - }; + useEffect(() => { + const id = setInterval(() => { + if (!play) return; + + const newSeconds = total - 1000; + + setTotal((prev) => prev - 1000); + + setTime({ + hours: Math.floor((newSeconds / (1000 * 60 * 60)) % 24) + .toString() + .padStart(2, "0"), + minutes: Math.floor((newSeconds / 1000 / 60) % 60) + .toString() + .padStart(2, "0"), + seconds: Math.floor((newSeconds / 1000) % 60) + .toString() + .padStart(2, "0"), + }); + + setOriginal((prev) => prev + 1000); + }, 1000); - const discardChanges = () => { - setEditMode(false); - }; + return () => clearInterval(id); + }, [play, total]); - const toggleCollapse = () => { - setCollapsed((prev) => !prev); - }; + console.log(total, time); return ( -
+
- -
- -
+ +
+ + + + + + + + + + + + + + + + +
+ {play && !edit && setPlay(false)} />} + {!play && !edit && setPlay(true)} />}
- {!collapsed && ( - <> - {isEditMode ? ( - - ) : ( - - )} - - - )}
diff --git a/src/components/admin/services/timer/Controls.jsx b/src/components/admin/services/timer/Controls.jsx index 29f764d75..6f1913d36 100644 --- a/src/components/admin/services/timer/Controls.jsx +++ b/src/components/admin/services/timer/Controls.jsx @@ -1,56 +1,22 @@ -import { Play, Pause, Undo2, Trash2, Pen, Check, X } from "lucide-react"; -import Tooltip from "./Tooltip"; +import { Trash2, Pen, Check } from "lucide-react"; -const Controls = ({ - isEditMode, - paused, - isComplete, - resumeTimer, - pauseTimer, - openEditMode, - resetTimer, - onRemove, - saveChanges, - discardChanges, - collapsed, -}) => ( -
- {!isEditMode ? ( - <> - {paused || isComplete ? ( - - - - ) : ( - - - - )} - {!collapsed && ( - <> - - - - - - - - )} - - - - - ) : ( - <> - - - - - - - - )} -
-); +const Controls = ({ edit, setEdit, onRemove }) => { + return ( +
+ {edit && ( + <> + setEdit(false)} /> + + + )} + {!edit && ( + <> + setEdit(true)} /> + + + )} +
+ ); +}; export default Controls; diff --git a/src/components/admin/services/timer/Display.jsx b/src/components/admin/services/timer/Display.jsx deleted file mode 100644 index edb4a9a5e..000000000 --- a/src/components/admin/services/timer/Display.jsx +++ /dev/null @@ -1,14 +0,0 @@ -const Display = ({ time }) => ( -
- {["Hours", "Minutes", "Seconds"].map((label) => ( -
-
- {time[label.toLowerCase()]} -
-
{label}
-
- ))} -
-); - -export default Display; diff --git a/src/components/admin/services/timer/EditMode.jsx b/src/components/admin/services/timer/EditMode.jsx deleted file mode 100644 index 66e616957..000000000 --- a/src/components/admin/services/timer/EditMode.jsx +++ /dev/null @@ -1,31 +0,0 @@ -import { - InputOTP, - InputOTPGroup, - InputOTPSeparator, - InputOTPSlot, -} from "@/components/ui/input-otp"; - -const EditMode = ({ value, onChange }) => ( - onChange(value)} - value={value} - className="mt-4" - > - - - - - - - - - - - - - - -); - -export default EditMode; diff --git a/src/components/admin/services/timer/Status.jsx b/src/components/admin/services/timer/Status.jsx deleted file mode 100644 index ca9c5188b..000000000 --- a/src/components/admin/services/timer/Status.jsx +++ /dev/null @@ -1,23 +0,0 @@ -const Status = ({ isComplete, paused }) => { - if (isComplete) { - return ( -
- Completed -
- ); - } - if (paused) { - return ( -
- Not Running -
- ); - } - return ( -
- Running -
- ); -}; - -export default Status; diff --git a/src/components/admin/services/timer/Tooltip.jsx b/src/components/admin/services/timer/Tooltip.jsx deleted file mode 100644 index 5bdf48d2c..000000000 --- a/src/components/admin/services/timer/Tooltip.jsx +++ /dev/null @@ -1,12 +0,0 @@ -const Tooltip = ({ children, text }) => { - return ( -
- {children} -
- {text} -
-
- ); -}; - -export default Tooltip; From 4eeb924935923c7eeb5268e04073b747f1505b0d Mon Sep 17 00:00:00 2001 From: shahdivyank Date: Mon, 5 Aug 2024 02:11:24 -0700 Subject: [PATCH 17/19] remove console logs --- src/components/admin/services/timer/Clock.jsx | 2 -- src/components/user/team/Details.jsx | 2 -- src/data/admin/Judges.js | 2 -- 3 files changed, 6 deletions(-) diff --git a/src/components/admin/services/timer/Clock.jsx b/src/components/admin/services/timer/Clock.jsx index 5e32d425d..2b7c53ef9 100644 --- a/src/components/admin/services/timer/Clock.jsx +++ b/src/components/admin/services/timer/Clock.jsx @@ -63,8 +63,6 @@ const Timer = ({ onRemove }) => { return () => clearInterval(id); }, [play, total]); - console.log(total, time); - return (
diff --git a/src/components/user/team/Details.jsx b/src/components/user/team/Details.jsx index 7f48be767..9044aabd4 100644 --- a/src/components/user/team/Details.jsx +++ b/src/components/user/team/Details.jsx @@ -40,8 +40,6 @@ const Details = ({ team }) => { }; const handleSave = async () => { - console.log(details); - if ( !( details.links.github === "" || diff --git a/src/data/admin/Judges.js b/src/data/admin/Judges.js index 2e1958e42..b94bb8ef7 100644 --- a/src/data/admin/Judges.js +++ b/src/data/admin/Judges.js @@ -60,8 +60,6 @@ export const COLUMNS = [ name, })); - console.log(photos); - const zip = new JSZip(); const folder = zip.folder(); From 98a7fded55372bac988d9d1c1357d0b5612e63a4 Mon Sep 17 00:00:00 2001 From: shahdivyank Date: Mon, 5 Aug 2024 02:20:39 -0700 Subject: [PATCH 18/19] shadcn migration to typescript --- components.json | 2 +- package-lock.json | 11 ++ package.json | 1 + .../timer/{Controls.jsx => Controls.tsx} | 8 +- .../services/timer/{Timer.jsx => Timer.tsx} | 8 +- src/components/ui/accordion.jsx | 53 ------- src/components/ui/accordion.tsx | 58 +++++++ .../ui/{alert-dialog.jsx => alert-dialog.tsx} | 54 +++++-- src/components/ui/{button.jsx => button.tsx} | 10 +- src/components/ui/{card.jsx => card.tsx} | 30 +++- src/components/ui/{chart.jsx => chart.tsx} | 142 ++++++++++++------ src/components/ui/checkbox.jsx | 26 ---- src/components/ui/checkbox.tsx | 30 ++++ .../ui/{input-otp.jsx => input-otp.tsx} | 44 +++--- src/components/ui/input.jsx | 20 --- src/components/ui/input.tsx | 25 +++ src/components/ui/{label.jsx => label.tsx} | 8 +- .../ui/{progress.jsx => progress.tsx} | 5 +- src/components/ui/{tabs.jsx => tabs.tsx} | 15 +- src/components/ui/textarea.jsx | 26 ---- src/components/ui/textarea.tsx | 24 +++ 21 files changed, 378 insertions(+), 222 deletions(-) rename src/components/admin/services/timer/{Controls.jsx => Controls.tsx} (72%) rename src/components/admin/services/timer/{Timer.jsx => Timer.tsx} (90%) delete mode 100644 src/components/ui/accordion.jsx create mode 100644 src/components/ui/accordion.tsx rename src/components/ui/{alert-dialog.jsx => alert-dialog.tsx} (64%) rename src/components/ui/{button.jsx => button.tsx} (87%) rename src/components/ui/{card.jsx => card.tsx} (59%) rename src/components/ui/{chart.jsx => chart.tsx} (64%) delete mode 100644 src/components/ui/checkbox.jsx create mode 100644 src/components/ui/checkbox.tsx rename src/components/ui/{input-otp.jsx => input-otp.tsx} (53%) delete mode 100644 src/components/ui/input.jsx create mode 100644 src/components/ui/input.tsx rename src/components/ui/{label.jsx => label.tsx} (61%) rename src/components/ui/{progress.jsx => progress.tsx} (76%) rename src/components/ui/{tabs.jsx => tabs.tsx} (73%) delete mode 100644 src/components/ui/textarea.jsx create mode 100644 src/components/ui/textarea.tsx diff --git a/components.json b/components.json index 7a83b770d..efd72b8d6 100644 --- a/components.json +++ b/components.json @@ -2,7 +2,7 @@ "$schema": "https://ui.shadcn.com/schema.json", "style": "default", "rsc": true, - "tsx": false, + "tsx": true, "tailwind": { "config": "tailwind.config.js", "css": "src/app/globals.css", diff --git a/package-lock.json b/package-lock.json index 7ade755d8..ddb2f303a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -60,6 +60,7 @@ "@types/node": "^20.14.10", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", + "@types/uuid": "^10.0.0", "autoprefixer": "^10.4.16", "cypress": "^13.12.0", "eslint": "^8.53.0", @@ -1668,6 +1669,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.1.1.tgz", "integrity": "sha512-0i/EKJ222Afa1FE0C6pNJxDq1itzcl3HChE9DwskA4th4KRse8ojx8a1nVcOjwJdbpDLcz7uol77yYnQNMHdKw==", + "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.0", "@radix-ui/react-compose-refs": "1.1.0", @@ -2965,6 +2967,13 @@ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" }, + "node_modules/@types/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/warning": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz", @@ -9017,6 +9026,7 @@ "version": "0.408.0", "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.408.0.tgz", "integrity": "sha512-8kETAAeWmOvtGIr7HPHm51DXoxlfkNncQ5FZWXR+abX8saQwMYXANWIkUstaYtcKSo/imOe/q+tVFA8ANzdSVA==", + "license": "ISC", "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } @@ -11686,6 +11696,7 @@ "version": "2.12.7", "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.12.7.tgz", "integrity": "sha512-hlLJMhPQfv4/3NBSAyq3gzGg4h2v69RJh6KU7b3pXYNNAELs9kEoXOjbkxdXpALqKBoVmVptGfLpxdaVYqjmXQ==", + "license": "MIT", "dependencies": { "clsx": "^2.0.0", "eventemitter3": "^4.0.1", diff --git a/package.json b/package.json index 438d25bf3..379418099 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,7 @@ "@types/node": "^20.14.10", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", + "@types/uuid": "^10.0.0", "autoprefixer": "^10.4.16", "cypress": "^13.12.0", "eslint": "^8.53.0", diff --git a/src/components/admin/services/timer/Controls.jsx b/src/components/admin/services/timer/Controls.tsx similarity index 72% rename from src/components/admin/services/timer/Controls.jsx rename to src/components/admin/services/timer/Controls.tsx index 6f1913d36..289808deb 100644 --- a/src/components/admin/services/timer/Controls.jsx +++ b/src/components/admin/services/timer/Controls.tsx @@ -1,6 +1,12 @@ import { Trash2, Pen, Check } from "lucide-react"; -const Controls = ({ edit, setEdit, onRemove }) => { +type props = { + edit: boolean; + setEdit: (value: boolean) => void; + onRemove: () => void; +}; + +const Controls = ({ edit, setEdit, onRemove }: props) => { return (
{edit && ( diff --git a/src/components/admin/services/timer/Timer.jsx b/src/components/admin/services/timer/Timer.tsx similarity index 90% rename from src/components/admin/services/timer/Timer.jsx rename to src/components/admin/services/timer/Timer.tsx index fbe244d9e..16106ef6c 100644 --- a/src/components/admin/services/timer/Timer.jsx +++ b/src/components/admin/services/timer/Timer.tsx @@ -4,8 +4,12 @@ import { v4 as uuidv4 } from "uuid"; import Title from "../../Title"; import { Button } from "@/components/ui/button"; +type TimerType = { + id: string; +}; + const Timer = () => { - const [timers, setTimers] = useState([]); + const [timers, setTimers] = useState([]); const addTimer = () => { setTimers([ @@ -20,7 +24,7 @@ const Timer = () => { setTimers([]); }; - const deleteTimer = (id) => { + const deleteTimer = (id: string) => { setTimers(timers.filter((timer) => timer.id !== id)); }; diff --git a/src/components/ui/accordion.jsx b/src/components/ui/accordion.jsx deleted file mode 100644 index f48dc5eaa..000000000 --- a/src/components/ui/accordion.jsx +++ /dev/null @@ -1,53 +0,0 @@ -"use client"; - -import * as React from "react"; -import * as AccordionPrimitive from "@radix-ui/react-accordion"; -import { ChevronDown } from "lucide-react"; - -import { cn } from "@/utils/tailwind"; - -const Accordion = AccordionPrimitive.Root; - -const AccordionItem = React.forwardRef(({ className, ...props }, ref) => ( - -)); -AccordionItem.displayName = "AccordionItem"; - -const AccordionTrigger = React.forwardRef( - ({ className, children, ...props }, ref) => ( - - svg]:rotate-180", - className, - )} - {...props} - > - {children} - - - - ), -); -AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName; - -const AccordionContent = React.forwardRef( - ({ className, children, ...props }, ref) => ( - -
{children}
-
- ), -); - -AccordionContent.displayName = AccordionPrimitive.Content.displayName; - -export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }; diff --git a/src/components/ui/accordion.tsx b/src/components/ui/accordion.tsx new file mode 100644 index 000000000..ff879aa31 --- /dev/null +++ b/src/components/ui/accordion.tsx @@ -0,0 +1,58 @@ +"use client"; + +import * as React from "react"; +import * as AccordionPrimitive from "@radix-ui/react-accordion"; +import { ChevronDown } from "lucide-react"; + +import { cn } from "@/utils/tailwind"; + +const Accordion = AccordionPrimitive.Root; + +const AccordionItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AccordionItem.displayName = "AccordionItem"; + +const AccordionTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + svg]:rotate-180", + className, + )} + {...props} + > + {children} + + + +)); +AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName; + +const AccordionContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + +
{children}
+
+)); + +AccordionContent.displayName = AccordionPrimitive.Content.displayName; + +export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }; diff --git a/src/components/ui/alert-dialog.jsx b/src/components/ui/alert-dialog.tsx similarity index 64% rename from src/components/ui/alert-dialog.jsx rename to src/components/ui/alert-dialog.tsx index cf05f8b33..801f12a5a 100644 --- a/src/components/ui/alert-dialog.jsx +++ b/src/components/ui/alert-dialog.tsx @@ -12,7 +12,10 @@ const AlertDialogTrigger = AlertDialogPrimitive.Trigger; const AlertDialogPortal = AlertDialogPrimitive.Portal; -const AlertDialogOverlay = React.forwardRef(({ className, ...props }, ref) => ( +const AlertDialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( ( )); AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName; -const AlertDialogContent = React.forwardRef(({ className, ...props }, ref) => ( +const AlertDialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( ( )); AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName; -const AlertDialogHeader = ({ className, ...props }) => ( +const AlertDialogHeader = ({ + className, + ...props +}: React.HTMLAttributes) => (
( ); AlertDialogHeader.displayName = "AlertDialogHeader"; -const AlertDialogFooter = ({ className, ...props }) => ( +const AlertDialogFooter = ({ + className, + ...props +}: React.HTMLAttributes) => (
( ); AlertDialogFooter.displayName = "AlertDialogFooter"; -const AlertDialogTitle = React.forwardRef(({ className, ...props }, ref) => ( +const AlertDialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( ( )); AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName; -const AlertDialogDescription = React.forwardRef( - ({ className, ...props }, ref) => ( - - ), -); +const AlertDialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName; -const AlertDialogAction = React.forwardRef(({ className, ...props }, ref) => ( +const AlertDialogAction = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( ( )); AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName; -const AlertDialogCancel = React.forwardRef(({ className, ...props }, ref) => ( +const AlertDialogCancel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( , + VariantProps { + asChild?: boolean; +} + +const Button = React.forwardRef( ({ className, variant, size, asChild = false, ...props }, ref) => { const Comp = asChild ? Slot : "button"; return ( diff --git a/src/components/ui/card.jsx b/src/components/ui/card.tsx similarity index 59% rename from src/components/ui/card.jsx rename to src/components/ui/card.tsx index 69e47bafa..725daa4e9 100644 --- a/src/components/ui/card.jsx +++ b/src/components/ui/card.tsx @@ -2,7 +2,10 @@ import * as React from "react"; import { cn } from "@/utils/tailwind"; -const Card = React.forwardRef(({ className, ...props }, ref) => ( +const Card = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => (
( )); Card.displayName = "Card"; -const CardHeader = React.forwardRef(({ className, ...props }, ref) => ( +const CardHeader = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => (
( )); CardHeader.displayName = "CardHeader"; -const CardTitle = React.forwardRef(({ className, ...props }, ref) => ( +const CardTitle = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => (

( )); CardTitle.displayName = "CardTitle"; -const CardDescription = React.forwardRef(({ className, ...props }, ref) => ( +const CardDescription = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => (

( )); CardDescription.displayName = "CardDescription"; -const CardContent = React.forwardRef(({ className, ...props }, ref) => ( +const CardContent = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => (

)); CardContent.displayName = "CardContent"; -const CardFooter = React.forwardRef(({ className, ...props }, ref) => ( +const CardFooter = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => (
} + ); +}; + +type ChartContextProps = { + config: ChartConfig; }; -const ChartContext = React.createContext(null); +const ChartContext = React.createContext(null); function useChart() { const context = React.useContext(ChartContext); @@ -22,34 +34,40 @@ function useChart() { return context; } -const ChartContainer = React.forwardRef( - ({ id, className, children, config, ...props }, ref) => { - const uniqueId = React.useId(); - const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`; +const ChartContainer = React.forwardRef< + HTMLDivElement, + React.ComponentProps<"div"> & { + config: ChartConfig; + children: React.ComponentProps< + typeof RechartsPrimitive.ResponsiveContainer + >["children"]; + } +>(({ id, className, children, config, ...props }, ref) => { + const uniqueId = React.useId(); + const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`; - return ( - -
- - - {children} - -
-
- ); - }, -); + return ( + +
+ + + {children} + +
+
+ ); +}); ChartContainer.displayName = "Chart"; -const ChartStyle = ({ id, config }) => { +const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => { const colorConfig = Object.entries(config).filter( ([_, config]) => config.theme || config.color, ); @@ -67,7 +85,9 @@ const ChartStyle = ({ id, config }) => { ${prefix} [data-chart=${id}] { ${colorConfig .map(([key, itemConfig]) => { - const color = itemConfig.theme?.[theme] || itemConfig.color; + const color = + itemConfig.theme?.[theme as keyof typeof itemConfig.theme] || + itemConfig.color; return color ? ` --color-${key}: ${color};` : null; }) .join("\n")} @@ -82,7 +102,17 @@ ${colorConfig const ChartTooltip = RechartsPrimitive.Tooltip; -const ChartTooltipContent = React.forwardRef( +const ChartTooltipContent = React.forwardRef< + HTMLDivElement, + React.ComponentProps & + React.ComponentProps<"div"> & { + hideLabel?: boolean; + hideIndicator?: boolean; + indicator?: "line" | "dot" | "dashed"; + nameKey?: string; + labelKey?: string; + } +>( ( { active, @@ -113,7 +143,7 @@ const ChartTooltipContent = React.forwardRef( const itemConfig = getPayloadConfigFromPayload(config, item, key); const value = !labelKey && typeof label === "string" - ? config[label]?.label || label + ? config[label as keyof typeof config]?.label || label : itemConfig?.label; if (labelFormatter) { @@ -164,7 +194,7 @@ const ChartTooltipContent = React.forwardRef(
svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-slate-500 dark:[&>svg]:text-slate-400", + "flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-slate-500 dark:[&>svg]:text-slate-400", indicator === "dot" && "items-center", )} > @@ -178,7 +208,7 @@ const ChartTooltipContent = React.forwardRef( !hideIndicator && (
) )} @@ -226,7 +258,14 @@ ChartTooltipContent.displayName = "ChartTooltip"; const ChartLegend = RechartsPrimitive.Legend; -const ChartLegendContent = React.forwardRef( +const ChartLegendContent = React.forwardRef< + HTMLDivElement, + React.ComponentProps<"div"> & + Pick & { + hideIcon?: boolean; + nameKey?: string; + } +>( ( { className, hideIcon = false, payload, verticalAlign = "bottom", nameKey }, ref, @@ -278,7 +317,11 @@ const ChartLegendContent = React.forwardRef( ChartLegendContent.displayName = "ChartLegend"; // Helper to extract item config from a payload. -function getPayloadConfigFromPayload(config, payload, key) { +function getPayloadConfigFromPayload( + config: ChartConfig, + payload: unknown, + key: string, +) { if (typeof payload !== "object" || payload === null) { return undefined; } @@ -290,19 +333,26 @@ function getPayloadConfigFromPayload(config, payload, key) { ? payload.payload : undefined; - let configLabelKey = key; + let configLabelKey: string = key; - if (key in payload && typeof payload[key] === "string") { - configLabelKey = payload[key]; + if ( + key in payload && + typeof payload[key as keyof typeof payload] === "string" + ) { + configLabelKey = payload[key as keyof typeof payload] as string; } else if ( payloadPayload && key in payloadPayload && - typeof payloadPayload[key] === "string" + typeof payloadPayload[key as keyof typeof payloadPayload] === "string" ) { - configLabelKey = payloadPayload[key]; + configLabelKey = payloadPayload[ + key as keyof typeof payloadPayload + ] as string; } - return configLabelKey in config ? config[configLabelKey] : config[key]; + return configLabelKey in config + ? config[configLabelKey] + : config[key as keyof typeof config]; } export { diff --git a/src/components/ui/checkbox.jsx b/src/components/ui/checkbox.jsx deleted file mode 100644 index e2be3c27a..000000000 --- a/src/components/ui/checkbox.jsx +++ /dev/null @@ -1,26 +0,0 @@ -"use client"; -import * as React from "react"; -import * as CheckboxPrimitive from "@radix-ui/react-checkbox"; -import { Check } from "lucide-react"; - -import { cn } from "@/utils/tailwind"; - -const Checkbox = React.forwardRef(({ className, ...props }, ref) => ( - - - - - -)); -Checkbox.displayName = CheckboxPrimitive.Root.displayName; - -export { Checkbox }; diff --git a/src/components/ui/checkbox.tsx b/src/components/ui/checkbox.tsx new file mode 100644 index 000000000..2c029e3c5 --- /dev/null +++ b/src/components/ui/checkbox.tsx @@ -0,0 +1,30 @@ +"use client"; + +import * as React from "react"; +import * as CheckboxPrimitive from "@radix-ui/react-checkbox"; +import { Check } from "lucide-react"; + +import { cn } from "@/utils/tailwind"; + +const Checkbox = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + + +)); +Checkbox.displayName = CheckboxPrimitive.Root.displayName; + +export { Checkbox }; diff --git a/src/components/ui/input-otp.jsx b/src/components/ui/input-otp.tsx similarity index 53% rename from src/components/ui/input-otp.jsx rename to src/components/ui/input-otp.tsx index 9b50be40d..7d98a42b0 100644 --- a/src/components/ui/input-otp.jsx +++ b/src/components/ui/input-otp.tsx @@ -6,27 +6,34 @@ import { Dot } from "lucide-react"; import { cn } from "@/utils/tailwind"; -const InputOTP = React.forwardRef( - ({ className, containerClassName, ...props }, ref) => ( - - ), -); +const InputOTP = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, containerClassName, ...props }, ref) => ( + +)); InputOTP.displayName = "InputOTP"; -const InputOTPGroup = React.forwardRef(({ className, ...props }, ref) => ( +const InputOTPGroup = React.forwardRef< + React.ElementRef<"div">, + React.ComponentPropsWithoutRef<"div"> +>(({ className, ...props }, ref) => (
)); InputOTPGroup.displayName = "InputOTPGroup"; -const InputOTPSlot = React.forwardRef(({ index, className, ...props }, ref) => { +const InputOTPSlot = React.forwardRef< + React.ElementRef<"div">, + React.ComponentPropsWithoutRef<"div"> & { index: number } +>(({ index, className, ...props }, ref) => { const inputOTPContext = React.useContext(OTPInputContext); const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index]; @@ -34,7 +41,7 @@ const InputOTPSlot = React.forwardRef(({ index, className, ...props }, ref) => {
{ }); InputOTPSlot.displayName = "InputOTPSlot"; -const InputOTPSeparator = React.forwardRef(({ ...props }, ref) => ( +const InputOTPSeparator = React.forwardRef< + React.ElementRef<"div">, + React.ComponentPropsWithoutRef<"div"> +>(({ ...props }, ref) => (
diff --git a/src/components/ui/input.jsx b/src/components/ui/input.jsx deleted file mode 100644 index c93d82d34..000000000 --- a/src/components/ui/input.jsx +++ /dev/null @@ -1,20 +0,0 @@ -import * as React from "react"; - -import { cn } from "@/utils/tailwind"; - -const Input = React.forwardRef(({ className, type, ...props }, ref) => { - return ( - - ); -}); -Input.displayName = "Input"; - -export { Input }; diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx new file mode 100644 index 000000000..2f0d9f3b4 --- /dev/null +++ b/src/components/ui/input.tsx @@ -0,0 +1,25 @@ +import * as React from "react"; + +import { cn } from "@/utils/tailwind"; + +export interface InputProps + extends React.InputHTMLAttributes {} + +const Input = React.forwardRef( + ({ className, type, ...props }, ref) => { + return ( + + ); + }, +); +Input.displayName = "Input"; + +export { Input }; diff --git a/src/components/ui/label.jsx b/src/components/ui/label.tsx similarity index 61% rename from src/components/ui/label.jsx rename to src/components/ui/label.tsx index e83a65957..47a250e12 100644 --- a/src/components/ui/label.jsx +++ b/src/components/ui/label.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import * as LabelPrimitive from "@radix-ui/react-label"; -import { cva } from "class-variance-authority"; +import { cva, type VariantProps } from "class-variance-authority"; import { cn } from "@/utils/tailwind"; @@ -10,7 +10,11 @@ const labelVariants = cva( "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70", ); -const Label = React.forwardRef(({ className, ...props }, ref) => ( +const Label = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps +>(({ className, ...props }, ref) => ( ( +const Progress = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, value, ...props }, ref) => ( ( +const TabsList = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( ( )); TabsList.displayName = TabsPrimitive.List.displayName; -const TabsTrigger = React.forwardRef(({ className, ...props }, ref) => ( +const TabsTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( ( )); TabsTrigger.displayName = TabsPrimitive.Trigger.displayName; -const TabsContent = React.forwardRef(({ className, ...props }, ref) => ( +const TabsContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( { - return ( -
-

- {title} - {required && *} -

-