forked from github/plane
feat: checkbox component (#3603)
* feat: custom checkbox component. * improvement: checkbox component implementation in email notification settings. * improvement: add loader in email notification settings page.
This commit is contained in:
parent
b86c6c906a
commit
1927fdd437
67
packages/ui/src/form-fields/checkbox.tsx
Normal file
67
packages/ui/src/form-fields/checkbox.tsx
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
export interface CheckboxProps extends React.InputHTMLAttributes<HTMLInputElement> {
|
||||||
|
intermediate?: boolean;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>((props, ref) => {
|
||||||
|
const { id, name, checked, intermediate = false, disabled, className = "", ...rest } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={`relative w-full flex gap-2 ${className}`}>
|
||||||
|
<input
|
||||||
|
id={id}
|
||||||
|
ref={ref}
|
||||||
|
type="checkbox"
|
||||||
|
name={name}
|
||||||
|
checked={checked}
|
||||||
|
className={`
|
||||||
|
appearance-none shrink-0 w-4 h-4 border rounded-[3px] focus:outline-1 focus:outline-offset-4 focus:outline-custom-primary-50
|
||||||
|
${
|
||||||
|
disabled
|
||||||
|
? "border-custom-border-200 bg-custom-background-80 cursor-not-allowed"
|
||||||
|
: `cursor-pointer ${
|
||||||
|
checked || intermediate
|
||||||
|
? "border-custom-primary-40 bg-custom-primary-100 hover:bg-custom-primary-200"
|
||||||
|
: "border-custom-border-300 hover:border-custom-border-400 bg-white"
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
disabled={disabled}
|
||||||
|
{...rest}
|
||||||
|
/>
|
||||||
|
<svg
|
||||||
|
className={`absolute w-4 h-4 p-0.5 pointer-events-none outline-none ${
|
||||||
|
disabled ? "stroke-custom-text-400 opacity-40" : "stroke-white"
|
||||||
|
} ${checked ? "block" : "hidden"}`}
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="3"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
>
|
||||||
|
<polyline points="20 6 9 17 4 12" />
|
||||||
|
</svg>
|
||||||
|
<svg
|
||||||
|
className={`absolute w-4 h-4 p-0.5 pointer-events-none outline-none ${
|
||||||
|
disabled ? "stroke-custom-text-400 opacity-40" : "stroke-white"
|
||||||
|
} ${intermediate && !checked ? "block" : "hidden"}`}
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 8 8"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="3"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
>
|
||||||
|
<path d="M5.75 4H2.25" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
Checkbox.displayName = "form-checkbox-field";
|
||||||
|
|
||||||
|
export { Checkbox };
|
@ -1,3 +1,4 @@
|
|||||||
export * from "./input";
|
export * from "./input";
|
||||||
export * from "./textarea";
|
export * from "./textarea";
|
||||||
export * from "./input-color-picker";
|
export * from "./input-color-picker";
|
||||||
|
export * from "./checkbox";
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
// ui
|
// ui
|
||||||
import { Button } from "@plane/ui";
|
import { Button, Checkbox } from "@plane/ui";
|
||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
// services
|
// services
|
||||||
@ -23,6 +23,7 @@ export const EmailNotificationForm: FC<IEmailNotificationFormProps> = (props) =>
|
|||||||
// form data
|
// form data
|
||||||
const {
|
const {
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
|
watch,
|
||||||
control,
|
control,
|
||||||
setValue,
|
setValue,
|
||||||
formState: { isSubmitting, isDirty, dirtyFields },
|
formState: { isSubmitting, isDirty, dirtyFields },
|
||||||
@ -78,12 +79,7 @@ export const EmailNotificationForm: FC<IEmailNotificationFormProps> = (props) =>
|
|||||||
control={control}
|
control={control}
|
||||||
name="property_change"
|
name="property_change"
|
||||||
render={({ field: { value, onChange } }) => (
|
render={({ field: { value, onChange } }) => (
|
||||||
<input
|
<Checkbox checked={value} onChange={() => onChange(!value)} className="mx-2" />
|
||||||
type="checkbox"
|
|
||||||
checked={value}
|
|
||||||
onChange={() => onChange(!value)}
|
|
||||||
className="w-3.5 h-3.5 mx-2 cursor-pointer !border-custom-border-100"
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -100,14 +96,14 @@ export const EmailNotificationForm: FC<IEmailNotificationFormProps> = (props) =>
|
|||||||
control={control}
|
control={control}
|
||||||
name="state_change"
|
name="state_change"
|
||||||
render={({ field: { value, onChange } }) => (
|
render={({ field: { value, onChange } }) => (
|
||||||
<input
|
<Checkbox
|
||||||
type="checkbox"
|
|
||||||
checked={value}
|
checked={value}
|
||||||
|
intermediate={!value && watch("issue_completed")}
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
setValue("issue_completed", !value);
|
setValue("issue_completed", !value);
|
||||||
onChange(!value);
|
onChange(!value);
|
||||||
}}
|
}}
|
||||||
className="w-3.5 h-3.5 mx-2 cursor-pointer"
|
className="mx-2"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@ -123,12 +119,7 @@ export const EmailNotificationForm: FC<IEmailNotificationFormProps> = (props) =>
|
|||||||
control={control}
|
control={control}
|
||||||
name="issue_completed"
|
name="issue_completed"
|
||||||
render={({ field: { value, onChange } }) => (
|
render={({ field: { value, onChange } }) => (
|
||||||
<input
|
<Checkbox checked={value} onChange={() => onChange(!value)} className="mx-2" />
|
||||||
type="checkbox"
|
|
||||||
checked={value}
|
|
||||||
onChange={() => onChange(!value)}
|
|
||||||
className="w-3.5 h-3.5 mx-2 cursor-pointer"
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -145,12 +136,7 @@ export const EmailNotificationForm: FC<IEmailNotificationFormProps> = (props) =>
|
|||||||
control={control}
|
control={control}
|
||||||
name="comment"
|
name="comment"
|
||||||
render={({ field: { value, onChange } }) => (
|
render={({ field: { value, onChange } }) => (
|
||||||
<input
|
<Checkbox checked={value} onChange={() => onChange(!value)} className="mx-2" />
|
||||||
type="checkbox"
|
|
||||||
checked={value}
|
|
||||||
onChange={() => onChange(!value)}
|
|
||||||
className="w-3.5 h-3.5 mx-2 cursor-pointer"
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -167,12 +153,7 @@ export const EmailNotificationForm: FC<IEmailNotificationFormProps> = (props) =>
|
|||||||
control={control}
|
control={control}
|
||||||
name="mention"
|
name="mention"
|
||||||
render={({ field: { value, onChange } }) => (
|
render={({ field: { value, onChange } }) => (
|
||||||
<input
|
<Checkbox checked={value} onChange={() => onChange(!value)} className="mx-2" />
|
||||||
type="checkbox"
|
|
||||||
checked={value}
|
|
||||||
onChange={() => onChange(!value)}
|
|
||||||
className="w-3.5 h-3.5 mx-2 cursor-pointer"
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,6 +2,8 @@ import { ReactElement } from "react";
|
|||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
// layouts
|
// layouts
|
||||||
import { ProfilePreferenceSettingsLayout } from "layouts/settings-layout/profile/preferences";
|
import { ProfilePreferenceSettingsLayout } from "layouts/settings-layout/profile/preferences";
|
||||||
|
// ui
|
||||||
|
import { Loader } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { EmailNotificationForm } from "components/profile/preferences";
|
import { EmailNotificationForm } from "components/profile/preferences";
|
||||||
// services
|
// services
|
||||||
@ -14,10 +16,20 @@ const userService = new UserService();
|
|||||||
|
|
||||||
const ProfilePreferencesThemePage: NextPageWithLayout = () => {
|
const ProfilePreferencesThemePage: NextPageWithLayout = () => {
|
||||||
// fetching user email notification settings
|
// fetching user email notification settings
|
||||||
const { data } = useSWR("CURRENT_USER_EMAIL_NOTIFICATION_SETTINGS", () =>
|
const { data, isLoading } = useSWR("CURRENT_USER_EMAIL_NOTIFICATION_SETTINGS", () =>
|
||||||
userService.currentUserEmailNotificationSettings()
|
userService.currentUserEmailNotificationSettings()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return (
|
||||||
|
<Loader className="space-y-4 mt-8 px-6 lg:px-20">
|
||||||
|
<Loader.Item height="40px" />
|
||||||
|
<Loader.Item height="40px" />
|
||||||
|
<Loader.Item height="40px" />
|
||||||
|
</Loader>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user