zapishis-client/apps/web/components/profile/checkbox-with-text.tsx
Vlad Chikalkin 10b36978fe
Feature/10 contacts (#16)
* apps/bot: add feature add contact

* apps/bot: check role 'master' before add contact

* apps/bot: rename createCustomer -> createUser

* remove ';'

* app/bot: add contact define name & phone

* apps/bot: check user already exists w/o telegramId (invited)

* Чтобы добавить контакт, сначала поделитесь своим номером телефона.

* apps/bot: create or update functions

* apps/bot: remove api.ts -> move getCustomer to packages/graphql/api

* packages/graphql: add api/customer tests

* tests for createOrUpdateClient

* fix(apps/web): user is undefined

* fix(apps/web): actions getCustomer

* feat(apps/web): update user photo on app launch

* rename page 'masters' -> 'contacts'

* feat(apps/web): add basic /contacts page

* fix app layout

* refactor customer queries

* add action getProfile

* get customer contacts

* use zustand for contacts

* add loading spinner

* rename filteredContacts -> contacts

* replace zustand with @tanstack/react-query

* profile: use react-query

* refactor updateRole function

* move updateRole closer to profile-card

* beautify actions

* add page 'profile/[telegramId]'

* profile: add button "message to telegram"

* profile: add call feature

* app/bot: normalize phone before register

* do not open keyboard on page load

* contacts: loading spinner

* telegram login: customer.active=true

* update name on telegram first login
2025-01-20 18:11:33 +03:00

62 lines
1.8 KiB
TypeScript

/* eslint-disable promise/prefer-await-to-then */
'use client';
import { Checkbox, type CheckboxProps } from '@repo/ui/components/ui/checkbox';
import { useState } from 'react';
import { useDebouncedCallback } from 'use-debounce';
type Props = Pick<CheckboxProps, 'checked'> & {
readonly description?: string;
readonly onChange?: (value: boolean) => Promise<void> | void;
readonly text: string;
};
export function CheckboxWithText({ checked: initialValue, description, onChange, text }: Props) {
const [checked, setChecked] = useState(initialValue);
const { debouncedCallback, isPending } = useDebouncedOnChangeCallback(onChange);
const handleChange = () => {
const newValue = !checked;
setChecked(newValue);
debouncedCallback(newValue);
};
return (
<div className="flex items-start space-x-2">
<Checkbox checked={checked} disabled={isPending} id="terms1" onCheckedChange={handleChange} />
<div className="grid gap-1.5 leading-none">
<label
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
htmlFor="terms1"
>
{text}
</label>
{description ? <p className="text-sm text-muted-foreground">{description}</p> : false}
</div>
</div>
);
}
function useDebouncedOnChangeCallback(
callback: ((value: boolean) => Promise<void> | void) | undefined,
) {
const [isPending, setIsPending] = useState(false);
const debouncedCallback = useDebouncedCallback((checked: boolean) => {
if (!callback) return;
setIsPending(true);
const result = callback(checked);
if (result instanceof Promise) {
result.finally(() => setIsPending(false));
} else {
setIsPending(false);
}
}, 300);
return {
debouncedCallback,
isPending,
};
}