Skip to content

Commit 585af6a

Browse files
committed
toggle component
1 parent 9901158 commit 585af6a

6 files changed

Lines changed: 62 additions & 104 deletions

File tree

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { Controller, type Control, type FieldValues, type Path } from "react-hook-form";
2+
3+
interface Props<T extends FieldValues> {
4+
control: Control<T>;
5+
name: Path<T>;
6+
disabled?: boolean;
7+
}
8+
9+
export default function ToggleSwitch<T extends FieldValues>({ control, name, disabled = false }: Props<T>) {
10+
return (
11+
<Controller
12+
name={name}
13+
control={control}
14+
render={({ field }) => (
15+
<div className="relative inline-flex items-center">
16+
<input
17+
id={`switch-${name}`}
18+
type="checkbox"
19+
disabled={disabled}
20+
checked={field.value}
21+
onChange={(e) => field.onChange(e.target.checked)}
22+
className="peer appearance-none w-11 h-4.5 rounded-full bg-gray-200 border border-gray-300
23+
checked:bg-gradient-to-r checked:from-purple-600 checked:to-purple-800
24+
transition-all duration-300 cursor-pointer"
25+
/>
26+
<label
27+
htmlFor={`switch-${name}`}
28+
className="absolute -top-[0.1rem] left-0 h-5.5 w-5.5 bg-white rounded-full shadow-md border border-gray-300
29+
transform transition-all duration-300 peer-checked:translate-x-5.5
30+
peer-active:scale-90 cursor-pointer"
31+
></label>
32+
</div>
33+
)}
34+
/>
35+
)
36+
}

Frontend/src/components/common/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ export { default as Popup } from './Popup';
77
export { default as Sidebar } from './Sidebar';
88
export { default as GoogleAuth } from './GoogleAuth';
99
export { default as PasswordInput } from './PasswordInput';
10+
export { default as ToggleSwitch } from './ToggleSwitch';

Frontend/src/components/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export { ConfirmMenu, Footer, Header, Loader, Pagination, Popup, Sidebar, PasswordInput,GoogleAuth } from './common';
1+
export { ConfirmMenu, Footer, Header, Loader, Pagination, Popup, Sidebar, PasswordInput,GoogleAuth, ToggleSwitch } from './common';
22
export { Advanced, Common, Headers } from './jobForm';
33
export { JobCard } from './jobs';
44
export { Layout } from './layout';

Frontend/src/components/jobForm/Common.tsx

Lines changed: 3 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Copy, HelpCircle } from 'lucide-react';
44
import type { JobDetails } from '../../types'
55
import type { UseFormRegister, Control, UseFormWatch, FieldErrors } from 'react-hook-form';
66
import { Controller } from "react-hook-form";
7+
import { ToggleSwitch } from '../common';
78

89
interface Props {
910
register: UseFormRegister<JobDetails>;
@@ -52,60 +53,15 @@ export default function Common({ register, control, watch, errors, emailNotifica
5253

5354
<div className="flex flex-wrap items-center gap-4">
5455
<div className="flex items-center gap-2">
55-
<Controller
56-
name="enabled"
57-
control={control}
58-
render={({ field }) => (
59-
<div className="relative inline-flex items-center">
60-
<input
61-
id="switch-job-enabled"
62-
type="checkbox"
63-
checked={field.value}
64-
onChange={(e) => field.onChange(e.target.checked)}
65-
className="peer appearance-none w-11 h-4.5 rounded-full bg-gray-200 border border-gray-300
66-
checked:bg-gradient-to-r checked:from-purple-600 checked:to-purple-800
67-
transition-all duration-300 cursor-pointer"
68-
/>
69-
<label
70-
htmlFor="switch-job-enabled"
71-
className="absolute -top-0.01 left-0 h-5.5 w-5.5 bg-white rounded-full shadow-md border border-gray-300
72-
transform transition-all duration-300 peer-checked:translate-x-5.5
73-
peer-active:scale-90 cursor-pointer"
74-
></label>
75-
</div>
76-
)}
77-
/>
56+
<ToggleSwitch control={control} name="enabled" />
7857
<label htmlFor="switch-job-enabled" className="font-medium text-gray-700">
7958
Enable job
8059
</label>
8160
</div>
8261

8362
{/* Enable Email */}
8463
<div className="flex items-center gap-2">
85-
<Controller
86-
name="email"
87-
control={control}
88-
render={({ field }) => (
89-
<div className="relative inline-flex items-center">
90-
<input
91-
id="switch-email-enabled"
92-
type="checkbox"
93-
checked={field.value}
94-
disabled={!emailNotifications}
95-
onChange={(e) => field.onChange(e.target.checked)}
96-
className="peer appearance-none w-11 h-4.5 rounded-full bg-gray-200 border border-gray-300
97-
checked:bg-gradient-to-r checked:from-purple-600 checked:to-purple-800
98-
transition-all duration-300 cursor-pointer"
99-
/>
100-
<label
101-
htmlFor="switch-email-enabled"
102-
className="absolute -top-0.01 left-0 h-5.5 w-5.5 bg-white rounded-full shadow-md border border-gray-300
103-
transform transition-all duration-300 peer-checked:translate-x-5.5
104-
peer-active:scale-90 cursor-pointer"
105-
></label>
106-
</div>
107-
)}
108-
/>
64+
<ToggleSwitch control={control} name="email" disabled={!emailNotifications} />
10965
<label htmlFor="switch-email-enabled" className="font-medium text-gray-700">
11066
Enable email
11167
</label>

Frontend/src/components/settings/Preference.tsx

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Controller, type Control } from 'react-hook-form';
22
import type { UserWithoutEmail } from '../../types'
3+
import { ToggleSwitch } from '../common';
34

45
interface Props {
56
control: Control<UserWithoutEmail>;
@@ -16,37 +17,29 @@ export default function Preference({ control }: Props) {
1617
<Controller name="mode"
1718
control={control}
1819
render={({ field }) => (
19-
<button
20-
type="button"
21-
onClick={() => field.onChange(field.value === "day" ? "dark" : "day")}
22-
className={`relative inline-flex h-6 w-11 items-center rounded-full transition ${field.value === 'dark' ? 'bg-purple-600' : 'bg-gray-300'
23-
}`}
24-
>
25-
<span
26-
className={`inline-block h-4 w-4 transform rounded-full bg-white transition ${field.value === 'dark' ? 'translate-x-6' : 'translate-x-1'
27-
}`}
20+
<div className="relative inline-flex items-center">
21+
<input
22+
id={`switch-theme-mode`}
23+
type="checkbox"
24+
checked={field.value === "dark"}
25+
onChange={() => field.onChange(field.value === "dark"? "day": "dark")}
26+
className="peer appearance-none w-11 h-4.5 rounded-full bg-gray-200 border border-gray-300
27+
checked:bg-gradient-to-r checked:from-purple-600 checked:to-purple-800
28+
transition-all duration-300 cursor-pointer"
2829
/>
29-
</button>
30+
<label
31+
htmlFor={`switch-theme-mode`}
32+
className="absolute -top-[0.1rem] left-0 h-5.5 w-5.5 bg-white rounded-full shadow-md border border-gray-300
33+
transform transition-all duration-300 peer-checked:translate-x-5.5
34+
peer-active:scale-90 cursor-pointer"
35+
></label>
36+
</div>
3037
)} />
3138
</div>
3239

3340
<div className="flex items-center justify-between">
3441
<span className=" text-gray-700">24-Hour Time Format</span>
35-
<Controller name="timeFormat24"
36-
control={control}
37-
render={({ field }) => (
38-
<button
39-
type="button"
40-
onClick={() => field.onChange(!field.value)}
41-
className={`relative inline-flex h-6 w-11 items-center rounded-full transition ${field.value ? 'bg-purple-600' : 'bg-gray-300'
42-
}`}
43-
>
44-
<span
45-
className={`inline-block h-4 w-4 transform rounded-full bg-white transition ${field.value ? 'translate-x-6' : 'translate-x-1'
46-
}`}
47-
/>
48-
</button>
49-
)} />
42+
<ToggleSwitch control={control} name="timeFormat24" />
5043
</div>
5144
</div>
5245
</div>

Frontend/src/pages/Settings.tsx

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { useConfirmExit } from '../hooks/useConfirmExit';
77
import { Controller, useForm } from 'react-hook-form';
88
import { zodResolver } from "@hookform/resolvers/zod";
99
import { settingsSchema } from '../schemas/authSchemas';
10+
import { ToggleSwitch } from '../components';
1011

1112
export default function SettingsPage() {
1213
const user = useAppSelector(state => state.auth.user);
@@ -110,41 +111,12 @@ export default function SettingsPage() {
110111
<div className="space-y-4">
111112
<div className="flex items-center justify-between">
112113
<span className=" text-gray-700">Email Notifications</span>
113-
<Controller name="emailNotifications"
114-
control={control}
115-
render={({ field }) => (
116-
<button
117-
type="button"
118-
onClick={() => field.onChange(!field.value)}
119-
className={`relative inline-flex h-6 w-11 items-center rounded-full transition ${field.value ? 'bg-purple-600' : 'bg-gray-300'
120-
}`}
121-
>
122-
<span
123-
className={`inline-block h-4 w-4 transform rounded-full bg-white transition ${field.value ? 'translate-x-6' : 'translate-x-1'
124-
}`}
125-
/>
126-
</button>
127-
)} />
114+
<ToggleSwitch control={control} name="emailNotifications" />
128115
</div>
129116

130117
<div className="flex items-center justify-between">
131118
<span className=" text-gray-700">Push Alerts</span>
132-
133-
<Controller name="pushAlerts"
134-
control={control}
135-
render={({ field }) => (
136-
<button
137-
type="button"
138-
onClick={() => field.onChange(!field.value)}
139-
className={`relative inline-flex h-6 w-11 items-center rounded-full transition ${field.value ? 'bg-purple-600' : 'bg-gray-300'
140-
}`}
141-
>
142-
<span
143-
className={`inline-block h-4 w-4 transform rounded-full bg-white transition ${field.value ? 'translate-x-6' : 'translate-x-1'
144-
}`}
145-
/>
146-
</button>
147-
)} />
119+
<ToggleSwitch control={control} name="pushAlerts" />
148120
</div>
149121
</div>
150122
</div>

0 commit comments

Comments
 (0)