feat: invite code
This commit is contained in:
		@@ -200,6 +200,7 @@ export type { FinishPauseByShiftIdResponse } from './models/FinishPauseByShiftId
 | 
				
			|||||||
export type { FinishPauseByUserIdResponse } from './models/FinishPauseByUserIdResponse';
 | 
					export type { FinishPauseByUserIdResponse } from './models/FinishPauseByUserIdResponse';
 | 
				
			||||||
export type { FinishShiftByIdResponse } from './models/FinishShiftByIdResponse';
 | 
					export type { FinishShiftByIdResponse } from './models/FinishShiftByIdResponse';
 | 
				
			||||||
export type { FinishShiftResponse } from './models/FinishShiftResponse';
 | 
					export type { FinishShiftResponse } from './models/FinishShiftResponse';
 | 
				
			||||||
 | 
					export type { GenerateInviteCodeRequest } from './models/GenerateInviteCodeRequest';
 | 
				
			||||||
export type { GenerateInviteCodeResponse } from './models/GenerateInviteCodeResponse';
 | 
					export type { GenerateInviteCodeResponse } from './models/GenerateInviteCodeResponse';
 | 
				
			||||||
export type { GetAllBarcodeTemplateAttributesResponse } from './models/GetAllBarcodeTemplateAttributesResponse';
 | 
					export type { GetAllBarcodeTemplateAttributesResponse } from './models/GetAllBarcodeTemplateAttributesResponse';
 | 
				
			||||||
export type { GetAllBarcodeTemplateSizesResponse } from './models/GetAllBarcodeTemplateSizesResponse';
 | 
					export type { GetAllBarcodeTemplateSizesResponse } from './models/GetAllBarcodeTemplateSizesResponse';
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@
 | 
				
			|||||||
import type { Body_upload_passport_image } from '../models/Body_upload_passport_image';
 | 
					import type { Body_upload_passport_image } from '../models/Body_upload_passport_image';
 | 
				
			||||||
import type { CreateUserRequest } from '../models/CreateUserRequest';
 | 
					import type { CreateUserRequest } from '../models/CreateUserRequest';
 | 
				
			||||||
import type { CreateUserResponse } from '../models/CreateUserResponse';
 | 
					import type { CreateUserResponse } from '../models/CreateUserResponse';
 | 
				
			||||||
 | 
					import type { GenerateInviteCodeRequest } from '../models/GenerateInviteCodeRequest';
 | 
				
			||||||
import type { GenerateInviteCodeResponse } from '../models/GenerateInviteCodeResponse';
 | 
					import type { GenerateInviteCodeResponse } from '../models/GenerateInviteCodeResponse';
 | 
				
			||||||
import type { GetAllUsersResponse } from '../models/GetAllUsersResponse';
 | 
					import type { GetAllUsersResponse } from '../models/GetAllUsersResponse';
 | 
				
			||||||
import type { GetManagersResponse } from '../models/GetManagersResponse';
 | 
					import type { GetManagersResponse } from '../models/GetManagersResponse';
 | 
				
			||||||
@@ -134,10 +135,19 @@ export class UserService {
 | 
				
			|||||||
     * @returns GenerateInviteCodeResponse Successful Response
 | 
					     * @returns GenerateInviteCodeResponse Successful Response
 | 
				
			||||||
     * @throws ApiError
 | 
					     * @throws ApiError
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public static generateInviteCode(): CancelablePromise<GenerateInviteCodeResponse> {
 | 
					    public static generateInviteCode({
 | 
				
			||||||
 | 
					        requestBody,
 | 
				
			||||||
 | 
					    }: {
 | 
				
			||||||
 | 
					        requestBody: GenerateInviteCodeRequest,
 | 
				
			||||||
 | 
					    }): CancelablePromise<GenerateInviteCodeResponse> {
 | 
				
			||||||
        return __request(OpenAPI, {
 | 
					        return __request(OpenAPI, {
 | 
				
			||||||
            method: 'POST',
 | 
					            method: 'POST',
 | 
				
			||||||
            url: '/user/generate-invite-code',
 | 
					            url: '/user/generate-invite-code',
 | 
				
			||||||
 | 
					            body: requestBody,
 | 
				
			||||||
 | 
					            mediaType: 'application/json',
 | 
				
			||||||
 | 
					            errors: {
 | 
				
			||||||
 | 
					                422: `Validation Error`,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,18 +1,15 @@
 | 
				
			|||||||
import { UserSchema, UserService } from "../../../../client";
 | 
					import { UserSchema } from "../../../../client";
 | 
				
			||||||
import { BaseTable } from "../../../../components/BaseTable/BaseTable.tsx";
 | 
					import { BaseTable } from "../../../../components/BaseTable/BaseTable.tsx";
 | 
				
			||||||
import { ActionIcon, Badge, Button, Flex, Input, rem, Text, Tooltip } from "@mantine/core";
 | 
					import { ActionIcon, Button, Flex, rem, Text, Tooltip } from "@mantine/core";
 | 
				
			||||||
import { useUsersTableColumns } from "./columns.tsx";
 | 
					import { useUsersTableColumns } from "./columns.tsx";
 | 
				
			||||||
import { IconEdit, IconQrcode, IconTrash } from "@tabler/icons-react";
 | 
					import { IconEdit, IconTrash } from "@tabler/icons-react";
 | 
				
			||||||
import { modals } from "@mantine/modals";
 | 
					import { modals } from "@mantine/modals";
 | 
				
			||||||
import { MRT_TableOptions } from "mantine-react-table";
 | 
					import { MRT_TableOptions } from "mantine-react-table";
 | 
				
			||||||
import { useUsersTabContext } from "../../tabs/Users/contexts/UsersTabContext.tsx";
 | 
					import { useUsersTabContext } from "../../tabs/Users/contexts/UsersTabContext.tsx";
 | 
				
			||||||
import { notifications } from "../../../../shared/lib/notifications.ts";
 | 
					 | 
				
			||||||
import { useClipboard } from "@mantine/hooks";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const UsersTable = () => {
 | 
					const UsersTable = () => {
 | 
				
			||||||
    const columns = useUsersTableColumns();
 | 
					    const columns = useUsersTableColumns();
 | 
				
			||||||
    const clipboard = useClipboard();
 | 
					 | 
				
			||||||
    const {
 | 
					    const {
 | 
				
			||||||
        usersCrud: {
 | 
					        usersCrud: {
 | 
				
			||||||
            items,
 | 
					            items,
 | 
				
			||||||
@@ -66,40 +63,7 @@ const UsersTable = () => {
 | 
				
			|||||||
            size: "md",
 | 
					            size: "md",
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    const onGenerateQrClick = (user: UserSchema) => {
 | 
					 | 
				
			||||||
        const pdfWindow = window.open(
 | 
					 | 
				
			||||||
            `${import.meta.env.VITE_API_URL}/work-shifts/generate-qr-code/${user.id}`,
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        if (!pdfWindow) return;
 | 
					 | 
				
			||||||
        pdfWindow.print();
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    const onCreateInviteCodeClick = async () => {
 | 
					 | 
				
			||||||
        const { inviteCode, ok, message } = await UserService.generateInviteCode();
 | 
					 | 
				
			||||||
        if (!ok || !inviteCode) {
 | 
					 | 
				
			||||||
            notifications.error({ message });
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        modals.openConfirmModal({
 | 
					 | 
				
			||||||
            withCloseButton: false,
 | 
					 | 
				
			||||||
            children: (
 | 
					 | 
				
			||||||
                <Flex gap={rem(10)} direction={"column"} justify={"center"} align={"center"}>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    <Text>
 | 
					 | 
				
			||||||
                        Ваш код приглашения!
 | 
					 | 
				
			||||||
                    </Text>
 | 
					 | 
				
			||||||
                    <Badge variant={"default"} style={{cursor:"text"}} radius={"sm"} size={"xl"}>{inviteCode}</Badge>
 | 
					 | 
				
			||||||
                    <Input.Description>
 | 
					 | 
				
			||||||
                        Код действителен в течении 30 минут
 | 
					 | 
				
			||||||
                    </Input.Description>
 | 
					 | 
				
			||||||
                </Flex>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
            labels: { confirm: "Скопировать", cancel: "Закрыть" },
 | 
					 | 
				
			||||||
            onConfirm: () => {
 | 
					 | 
				
			||||||
                clipboard.copy(inviteCode);
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <BaseTable
 | 
					        <BaseTable
 | 
				
			||||||
            data={items}
 | 
					            data={items}
 | 
				
			||||||
@@ -117,14 +81,7 @@ const UsersTable = () => {
 | 
				
			|||||||
                                    onClick={() => onCreateClick()}>
 | 
					                                    onClick={() => onCreateClick()}>
 | 
				
			||||||
                                    Создать пользователя
 | 
					                                    Создать пользователя
 | 
				
			||||||
                                </Button>
 | 
					                                </Button>
 | 
				
			||||||
                                <Button
 | 
					 | 
				
			||||||
                                    onClick={() => onCreateInviteCodeClick()}
 | 
					 | 
				
			||||||
                                    variant={"default"}
 | 
					 | 
				
			||||||
                                >
 | 
					 | 
				
			||||||
                                    Создать код приглашения
 | 
					 | 
				
			||||||
                                </Button>
 | 
					 | 
				
			||||||
                            </Flex>
 | 
					                            </Flex>
 | 
				
			||||||
 | 
					 | 
				
			||||||
                        </Flex>
 | 
					                        </Flex>
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
                    enableRowActions: true,
 | 
					                    enableRowActions: true,
 | 
				
			||||||
@@ -148,15 +105,7 @@ const UsersTable = () => {
 | 
				
			|||||||
                                    <IconTrash />
 | 
					                                    <IconTrash />
 | 
				
			||||||
                                </ActionIcon>
 | 
					                                </ActionIcon>
 | 
				
			||||||
                            </Tooltip>
 | 
					                            </Tooltip>
 | 
				
			||||||
                            <Tooltip
 | 
					
 | 
				
			||||||
                                onClick={() => {
 | 
					 | 
				
			||||||
                                    onGenerateQrClick(row.original);
 | 
					 | 
				
			||||||
                                }}
 | 
					 | 
				
			||||||
                                label="QR-код">
 | 
					 | 
				
			||||||
                                <ActionIcon variant={"default"}>
 | 
					 | 
				
			||||||
                                    <IconQrcode />
 | 
					 | 
				
			||||||
                                </ActionIcon>
 | 
					 | 
				
			||||||
                            </Tooltip>
 | 
					 | 
				
			||||||
                        </Flex>
 | 
					                        </Flex>
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
                } as MRT_TableOptions<UserSchema>
 | 
					                } as MRT_TableOptions<UserSchema>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,12 +17,13 @@ const UserFormModal = ({
 | 
				
			|||||||
                           id,
 | 
					                           id,
 | 
				
			||||||
                           innerProps,
 | 
					                           innerProps,
 | 
				
			||||||
                       }: ContextModalProps<Props>) => {
 | 
					                       }: ContextModalProps<Props>) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const isEditing = "element" in innerProps;
 | 
					    const isEditing = "element" in innerProps;
 | 
				
			||||||
    const [modalTab, setModalTab] = useState<ModalTab>(ModalTab.COMMON);
 | 
					    const [modalTab, setModalTab] = useState<ModalTab>(ModalTab.COMMON);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const closeModal = () => {
 | 
					    const closeModal = () => {
 | 
				
			||||||
        context.closeContextModal(id);
 | 
					        context.closeContextModal(id);
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!isEditing) {
 | 
					    if (!isEditing) {
 | 
				
			||||||
        return (
 | 
					        return (
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,9 @@
 | 
				
			|||||||
import { UserRoleEnum } from "../../../../../../shared/enums/UserRole.ts";
 | 
					import { UserRoleEnum } from "../../../../../../shared/enums/UserRole.ts";
 | 
				
			||||||
import { useForm } from "@mantine/form";
 | 
					import { useForm } from "@mantine/form";
 | 
				
			||||||
import { UserSchema } from "../../../../../../client";
 | 
					import { UserSchema, UserService } from "../../../../../../client";
 | 
				
			||||||
import phone from "phone";
 | 
					import phone from "phone";
 | 
				
			||||||
import BaseFormModal, { CreateEditFormProps } from "../../../../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
 | 
					import BaseFormModal, { CreateEditFormProps } from "../../../../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
 | 
				
			||||||
import { Checkbox, Fieldset, Input, Stack, Textarea, TextInput } from "@mantine/core";
 | 
					import { Badge, Button, Checkbox, Fieldset, Flex, Input, rem, Stack, Text, Textarea, TextInput } from "@mantine/core";
 | 
				
			||||||
import { capitalize } from "lodash";
 | 
					import { capitalize } from "lodash";
 | 
				
			||||||
import { IMaskInput } from "react-imask";
 | 
					import { IMaskInput } from "react-imask";
 | 
				
			||||||
import PassportImageDropzone from "../../../../components/PassportImageDropzone/PassportImageDropzone.tsx";
 | 
					import PassportImageDropzone from "../../../../components/PassportImageDropzone/PassportImageDropzone.tsx";
 | 
				
			||||||
@@ -11,6 +11,9 @@ import { BaseFormInputProps } from "../../../../../../types/utils.ts";
 | 
				
			|||||||
import RoleSelect from "../../../../components/RoleSelect/RoleSelect.tsx";
 | 
					import RoleSelect from "../../../../components/RoleSelect/RoleSelect.tsx";
 | 
				
			||||||
import PositionSelect from "../../../../components/PositionSelect/PositionSelect.tsx";
 | 
					import PositionSelect from "../../../../components/PositionSelect/PositionSelect.tsx";
 | 
				
			||||||
import PayRateSelect from "../../../../../../components/Selects/PayRateSelect/PayRateSelect.tsx";
 | 
					import PayRateSelect from "../../../../../../components/Selects/PayRateSelect/PayRateSelect.tsx";
 | 
				
			||||||
 | 
					import { useClipboard } from "@mantine/hooks";
 | 
				
			||||||
 | 
					import { notifications } from "../../../../../../shared/lib/notifications.ts";
 | 
				
			||||||
 | 
					import { modals } from "@mantine/modals";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Props = {
 | 
					type Props = {
 | 
				
			||||||
@@ -23,6 +26,47 @@ const CommonTab = ({
 | 
				
			|||||||
                       formProps,
 | 
					                       formProps,
 | 
				
			||||||
                   }: Props) => {
 | 
					                   }: Props) => {
 | 
				
			||||||
    const isEditing = "element" in formProps;
 | 
					    const isEditing = "element" in formProps;
 | 
				
			||||||
 | 
					    const clipboard = useClipboard();
 | 
				
			||||||
 | 
					    const onCreateInviteCodeClick = async () => {
 | 
				
			||||||
 | 
					        if (!isEditing) return;
 | 
				
			||||||
 | 
					        const {
 | 
				
			||||||
 | 
					            inviteCode,
 | 
				
			||||||
 | 
					            ok,
 | 
				
			||||||
 | 
					            message,
 | 
				
			||||||
 | 
					        } = await UserService.generateInviteCode({ requestBody: { userId: formProps.element.id } });
 | 
				
			||||||
 | 
					        if (!ok || !inviteCode) {
 | 
				
			||||||
 | 
					            notifications.error({ message });
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        modals.openConfirmModal({
 | 
				
			||||||
 | 
					            withCloseButton: false,
 | 
				
			||||||
 | 
					            children: (
 | 
				
			||||||
 | 
					                <Flex gap={rem(10)} direction={"column"} justify={"center"} align={"center"}>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <Text>
 | 
				
			||||||
 | 
					                        Ваш код приглашения!
 | 
				
			||||||
 | 
					                    </Text>
 | 
				
			||||||
 | 
					                    <Badge variant={"default"} style={{ cursor: "text" }} radius={"sm"} size={"xl"}>{inviteCode}</Badge>
 | 
				
			||||||
 | 
					                    <Input.Description>
 | 
				
			||||||
 | 
					                        Код действителен в течении 30 минут
 | 
				
			||||||
 | 
					                    </Input.Description>
 | 
				
			||||||
 | 
					                </Flex>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            labels: { confirm: "Скопировать", cancel: "Закрыть" },
 | 
				
			||||||
 | 
					            onConfirm: () => {
 | 
				
			||||||
 | 
					                clipboard.copy(inviteCode);
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    const onGenerateQrClick = () => {
 | 
				
			||||||
 | 
					        if (!isEditing) return;
 | 
				
			||||||
 | 
					        const pdfWindow = window.open(
 | 
				
			||||||
 | 
					            `${import.meta.env.VITE_API_URL}/work-shifts/generate-qr-code/${formProps.element.id}`,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        if (!pdfWindow) return;
 | 
				
			||||||
 | 
					        pdfWindow.print();
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
    const initialValues = isEditing
 | 
					    const initialValues = isEditing
 | 
				
			||||||
        ? formProps.element
 | 
					        ? formProps.element
 | 
				
			||||||
        : {
 | 
					        : {
 | 
				
			||||||
@@ -189,6 +233,15 @@ const CommonTab = ({
 | 
				
			|||||||
                            />
 | 
					                            />
 | 
				
			||||||
                        </Stack>
 | 
					                        </Stack>
 | 
				
			||||||
                    </Fieldset>
 | 
					                    </Fieldset>
 | 
				
			||||||
 | 
					                    {isEditing && (
 | 
				
			||||||
 | 
					                        <Fieldset pt={rem(20)}>
 | 
				
			||||||
 | 
					                            <Flex h={"100%"} justify={"center"} gap={rem(10)} direction={"column"}>
 | 
				
			||||||
 | 
					                                <Button onClick={() => onCreateInviteCodeClick()} variant={"default"}>Код
 | 
				
			||||||
 | 
					                                    приглашения</Button>
 | 
				
			||||||
 | 
					                                <Button onClick={() => onGenerateQrClick()} variant={"default"}>QR Код</Button>
 | 
				
			||||||
 | 
					                            </Flex>
 | 
				
			||||||
 | 
					                        </Fieldset>)
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                </>
 | 
					                </>
 | 
				
			||||||
            </BaseFormModal.Body>
 | 
					            </BaseFormModal.Body>
 | 
				
			||||||
        </BaseFormModal>
 | 
					        </BaseFormModal>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user