feat: invite code

This commit is contained in:
2025-03-05 19:36:35 +03:00
parent 6cc61dbf08
commit f8feea07c4
5 changed files with 73 additions and 59 deletions

View File

@@ -200,6 +200,7 @@ export type { FinishPauseByShiftIdResponse } from './models/FinishPauseByShiftId
export type { FinishPauseByUserIdResponse } from './models/FinishPauseByUserIdResponse';
export type { FinishShiftByIdResponse } from './models/FinishShiftByIdResponse';
export type { FinishShiftResponse } from './models/FinishShiftResponse';
export type { GenerateInviteCodeRequest } from './models/GenerateInviteCodeRequest';
export type { GenerateInviteCodeResponse } from './models/GenerateInviteCodeResponse';
export type { GetAllBarcodeTemplateAttributesResponse } from './models/GetAllBarcodeTemplateAttributesResponse';
export type { GetAllBarcodeTemplateSizesResponse } from './models/GetAllBarcodeTemplateSizesResponse';

View File

@@ -5,6 +5,7 @@
import type { Body_upload_passport_image } from '../models/Body_upload_passport_image';
import type { CreateUserRequest } from '../models/CreateUserRequest';
import type { CreateUserResponse } from '../models/CreateUserResponse';
import type { GenerateInviteCodeRequest } from '../models/GenerateInviteCodeRequest';
import type { GenerateInviteCodeResponse } from '../models/GenerateInviteCodeResponse';
import type { GetAllUsersResponse } from '../models/GetAllUsersResponse';
import type { GetManagersResponse } from '../models/GetManagersResponse';
@@ -134,10 +135,19 @@ export class UserService {
* @returns GenerateInviteCodeResponse Successful Response
* @throws ApiError
*/
public static generateInviteCode(): CancelablePromise<GenerateInviteCodeResponse> {
public static generateInviteCode({
requestBody,
}: {
requestBody: GenerateInviteCodeRequest,
}): CancelablePromise<GenerateInviteCodeResponse> {
return __request(OpenAPI, {
method: 'POST',
url: '/user/generate-invite-code',
body: requestBody,
mediaType: 'application/json',
errors: {
422: `Validation Error`,
},
});
}
}

View File

@@ -1,18 +1,15 @@
import { UserSchema, UserService } from "../../../../client";
import { UserSchema } from "../../../../client";
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 { IconEdit, IconQrcode, IconTrash } from "@tabler/icons-react";
import { IconEdit, IconTrash } from "@tabler/icons-react";
import { modals } from "@mantine/modals";
import { MRT_TableOptions } from "mantine-react-table";
import { useUsersTabContext } from "../../tabs/Users/contexts/UsersTabContext.tsx";
import { notifications } from "../../../../shared/lib/notifications.ts";
import { useClipboard } from "@mantine/hooks";
const UsersTable = () => {
const columns = useUsersTableColumns();
const clipboard = useClipboard();
const {
usersCrud: {
items,
@@ -66,40 +63,7 @@ const UsersTable = () => {
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 (
<BaseTable
data={items}
@@ -117,14 +81,7 @@ const UsersTable = () => {
onClick={() => onCreateClick()}>
Создать пользователя
</Button>
<Button
onClick={() => onCreateInviteCodeClick()}
variant={"default"}
>
Создать код приглашения
</Button>
</Flex>
</Flex>
),
enableRowActions: true,
@@ -148,15 +105,7 @@ const UsersTable = () => {
<IconTrash />
</ActionIcon>
</Tooltip>
<Tooltip
onClick={() => {
onGenerateQrClick(row.original);
}}
label="QR-код">
<ActionIcon variant={"default"}>
<IconQrcode />
</ActionIcon>
</Tooltip>
</Flex>
),
} as MRT_TableOptions<UserSchema>

View File

@@ -17,12 +17,13 @@ const UserFormModal = ({
id,
innerProps,
}: ContextModalProps<Props>) => {
const isEditing = "element" in innerProps;
const [modalTab, setModalTab] = useState<ModalTab>(ModalTab.COMMON);
const closeModal = () => {
context.closeContextModal(id);
}
};
if (!isEditing) {
return (

View File

@@ -1,9 +1,9 @@
import { UserRoleEnum } from "../../../../../../shared/enums/UserRole.ts";
import { useForm } from "@mantine/form";
import { UserSchema } from "../../../../../../client";
import { UserSchema, UserService } from "../../../../../../client";
import phone from "phone";
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 { IMaskInput } from "react-imask";
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 PositionSelect from "../../../../components/PositionSelect/PositionSelect.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 = {
@@ -23,6 +26,47 @@ const CommonTab = ({
formProps,
}: Props) => {
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
? formProps.element
: {
@@ -189,6 +233,15 @@ const CommonTab = ({
/>
</Stack>
</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>