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 { 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';
|
||||||
export type { GetAllBarcodeTemplatesResponse } from './models/GetAllBarcodeTemplatesResponse';
|
export type { GetAllBarcodeTemplatesResponse } from './models/GetAllBarcodeTemplatesResponse';
|
||||||
|
|||||||
@@ -8,5 +8,6 @@ export type AuthLoginRequest = {
|
|||||||
hash: string;
|
hash: string;
|
||||||
id: number;
|
id: number;
|
||||||
photo_url?: (string | null);
|
photo_url?: (string | null);
|
||||||
|
invite_code?: (string | null);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
10
src/client/models/GenerateInviteCodeResponse.ts
Normal file
10
src/client/models/GenerateInviteCodeResponse.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
/* generated using openapi-typescript-codegen -- do not edit */
|
||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
export type GenerateInviteCodeResponse = {
|
||||||
|
ok: boolean;
|
||||||
|
message: string;
|
||||||
|
inviteCode?: (string | null);
|
||||||
|
};
|
||||||
|
|
||||||
@@ -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 { 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';
|
||||||
import type { UpdateUserDepartmentSectionsRequest } from '../models/UpdateUserDepartmentSectionsRequest';
|
import type { UpdateUserDepartmentSectionsRequest } from '../models/UpdateUserDepartmentSectionsRequest';
|
||||||
@@ -128,4 +129,15 @@ export class UserService {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Generate Invite Code
|
||||||
|
* @returns GenerateInviteCodeResponse Successful Response
|
||||||
|
* @throws ApiError
|
||||||
|
*/
|
||||||
|
public static generateInviteCode(): CancelablePromise<GenerateInviteCodeResponse> {
|
||||||
|
return __request(OpenAPI, {
|
||||||
|
method: 'POST',
|
||||||
|
url: '/user/generate-invite-code',
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
import { UserSchema } from "../../../../client";
|
import { UserSchema, UserService } from "../../../../client";
|
||||||
import { BaseTable } from "../../../../components/BaseTable/BaseTable.tsx";
|
import { BaseTable } from "../../../../components/BaseTable/BaseTable.tsx";
|
||||||
import { ActionIcon, Button, Flex, rem, Text, Tooltip } from "@mantine/core";
|
import { ActionIcon, Badge, Button, Flex, Input, 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, IconQrcode, 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,
|
||||||
@@ -71,6 +73,33 @@ const UsersTable = () => {
|
|||||||
if (!pdfWindow) return;
|
if (!pdfWindow) return;
|
||||||
pdfWindow.print();
|
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}
|
||||||
@@ -82,11 +111,20 @@ const UsersTable = () => {
|
|||||||
enableTopToolbar: true,
|
enableTopToolbar: true,
|
||||||
renderTopToolbar: (
|
renderTopToolbar: (
|
||||||
<Flex p={rem(10)}>
|
<Flex p={rem(10)}>
|
||||||
|
<Flex gap={rem(10)}>
|
||||||
<Button
|
<Button
|
||||||
variant={"default"}
|
variant={"default"}
|
||||||
onClick={() => onCreateClick()}>
|
onClick={() => onCreateClick()}>
|
||||||
Создать пользователя
|
Создать пользователя
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={() => onCreateInviteCodeClick()}
|
||||||
|
variant={"default"}
|
||||||
|
>
|
||||||
|
Создать код приглашения
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
</Flex>
|
</Flex>
|
||||||
),
|
),
|
||||||
enableRowActions: true,
|
enableRowActions: true,
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
import { Button, Container, Paper, Title } from "@mantine/core";
|
import { Button, Checkbox, Container, Paper, Stack, TextInput, Title } from "@mantine/core";
|
||||||
import classes from "./LoginPage.module.scss";
|
import classes from "./LoginPage.module.scss";
|
||||||
import { RootState, useAppDispatch } from "../../redux/store.ts";
|
import { RootState, useAppDispatch } from "../../redux/store.ts";
|
||||||
import { AuthService } from "../../client";
|
import { ApiError, AuthService } from "../../client";
|
||||||
import TelegramLoginButton, {
|
import TelegramLoginButton, { TelegramUser } from "../../components/TelegramAuthButton/TelegramAuthButton.tsx";
|
||||||
TelegramUser,
|
|
||||||
} from "../../components/TelegramAuthButton/TelegramAuthButton.tsx";
|
|
||||||
import { notifications } from "../../shared/lib/notifications.ts";
|
import { notifications } from "../../shared/lib/notifications.ts";
|
||||||
import { login } from "../../features/authSlice.ts";
|
import { login } from "../../features/authSlice.ts";
|
||||||
import { Navigate, useNavigate } from "@tanstack/react-router";
|
import { Navigate, useNavigate } from "@tanstack/react-router";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import { useEffect } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
const LoginPage = () => {
|
const LoginPage = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const authState = useSelector((state: RootState) => state.auth);
|
const authState = useSelector((state: RootState) => state.auth);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const [hasInviteCode, setHasInviteCode] = useState(false);
|
||||||
|
const [inviteCode, setInviteCode] = useState("");
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (authState.isAuthorized)
|
if (authState.isAuthorized)
|
||||||
// ???????????
|
// ???????????
|
||||||
@@ -45,9 +45,12 @@ const LoginPage = () => {
|
|||||||
radius="md">
|
radius="md">
|
||||||
<TelegramLoginButton
|
<TelegramLoginButton
|
||||||
botName={"DencoFulfillmentTestBot"}
|
botName={"DencoFulfillmentTestBot"}
|
||||||
dataOnauth={() => {}}
|
dataOnauth={() => {
|
||||||
|
}}
|
||||||
wrapperProps={{ style: { display: "none" } }}
|
wrapperProps={{ style: { display: "none" } }}
|
||||||
/>
|
/>
|
||||||
|
<Stack>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
fullWidth
|
fullWidth
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@@ -60,23 +63,37 @@ const LoginPage = () => {
|
|||||||
},
|
},
|
||||||
(data: TelegramUser) => {
|
(data: TelegramUser) => {
|
||||||
AuthService.loginAuthLoginPost({
|
AuthService.loginAuthLoginPost({
|
||||||
requestBody: data,
|
requestBody: {...data, invite_code: inviteCode.trim() ? inviteCode : undefined},
|
||||||
})
|
})
|
||||||
.then(({ accessToken }) => {
|
.then(({ accessToken }) => {
|
||||||
dispatch(
|
dispatch(
|
||||||
login({ accessToken: accessToken })
|
login({ accessToken: accessToken }),
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch((reason: ApiError) => {
|
||||||
|
const message = reason?.body?.detail.toString() || "Ошибка авторизации";
|
||||||
notifications.error({
|
notifications.error({
|
||||||
message: "Неудалось войти!",
|
message,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}}>
|
}}>
|
||||||
Войти через Telegram
|
Войти через Telegram
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
{!hasInviteCode ? (
|
||||||
|
<Checkbox label={"У меня есть код подключения"} checked={hasInviteCode}
|
||||||
|
onChange={event => setHasInviteCode(event.target.checked)} />) : (
|
||||||
|
<TextInput
|
||||||
|
value={inviteCode}
|
||||||
|
onChange={event => setInviteCode(event.currentTarget.value)}
|
||||||
|
placeholder={"Введите код подключения"}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
</Stack>
|
||||||
|
|
||||||
</Paper>
|
</Paper>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
/* prettier-ignore-start */
|
|
||||||
|
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
|
|
||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
|
|
||||||
// noinspection JSUnusedGlobalSymbols
|
// noinspection JSUnusedGlobalSymbols
|
||||||
|
|
||||||
// This file is auto-generated by TanStack Router
|
// This file was automatically generated by TanStack Router.
|
||||||
|
// You should NOT make any changes in this file as it will be overwritten.
|
||||||
|
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
|
||||||
|
|
||||||
import { createFileRoute } from '@tanstack/react-router'
|
import { createFileRoute } from '@tanstack/react-router'
|
||||||
|
|
||||||
@@ -36,16 +36,19 @@ const IndexLazyImport = createFileRoute('/')()
|
|||||||
// Create/Update Routes
|
// Create/Update Routes
|
||||||
|
|
||||||
const TestLazyRoute = TestLazyImport.update({
|
const TestLazyRoute = TestLazyImport.update({
|
||||||
|
id: '/test',
|
||||||
path: '/test',
|
path: '/test',
|
||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
} as any).lazy(() => import('./routes/test.lazy').then((d) => d.Route))
|
} as any).lazy(() => import('./routes/test.lazy').then((d) => d.Route))
|
||||||
|
|
||||||
const StatisticsLazyRoute = StatisticsLazyImport.update({
|
const StatisticsLazyRoute = StatisticsLazyImport.update({
|
||||||
|
id: '/statistics',
|
||||||
path: '/statistics',
|
path: '/statistics',
|
||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
} as any).lazy(() => import('./routes/statistics.lazy').then((d) => d.Route))
|
} as any).lazy(() => import('./routes/statistics.lazy').then((d) => d.Route))
|
||||||
|
|
||||||
const ShippingwarehousesLazyRoute = ShippingwarehousesLazyImport.update({
|
const ShippingwarehousesLazyRoute = ShippingwarehousesLazyImport.update({
|
||||||
|
id: '/shipping_warehouses',
|
||||||
path: '/shipping_warehouses',
|
path: '/shipping_warehouses',
|
||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
} as any).lazy(() =>
|
} as any).lazy(() =>
|
||||||
@@ -53,66 +56,79 @@ const ShippingwarehousesLazyRoute = ShippingwarehousesLazyImport.update({
|
|||||||
)
|
)
|
||||||
|
|
||||||
const ServicesLazyRoute = ServicesLazyImport.update({
|
const ServicesLazyRoute = ServicesLazyImport.update({
|
||||||
|
id: '/services',
|
||||||
path: '/services',
|
path: '/services',
|
||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
} as any).lazy(() => import('./routes/services.lazy').then((d) => d.Route))
|
} as any).lazy(() => import('./routes/services.lazy').then((d) => d.Route))
|
||||||
|
|
||||||
const ResiduesLazyRoute = ResiduesLazyImport.update({
|
const ResiduesLazyRoute = ResiduesLazyImport.update({
|
||||||
|
id: '/residues',
|
||||||
path: '/residues',
|
path: '/residues',
|
||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
} as any).lazy(() => import('./routes/residues.lazy').then((d) => d.Route))
|
} as any).lazy(() => import('./routes/residues.lazy').then((d) => d.Route))
|
||||||
|
|
||||||
const ReceiptLazyRoute = ReceiptLazyImport.update({
|
const ReceiptLazyRoute = ReceiptLazyImport.update({
|
||||||
|
id: '/receipt',
|
||||||
path: '/receipt',
|
path: '/receipt',
|
||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
} as any).lazy(() => import('./routes/receipt.lazy').then((d) => d.Route))
|
} as any).lazy(() => import('./routes/receipt.lazy').then((d) => d.Route))
|
||||||
|
|
||||||
const ProductsLazyRoute = ProductsLazyImport.update({
|
const ProductsLazyRoute = ProductsLazyImport.update({
|
||||||
|
id: '/products',
|
||||||
path: '/products',
|
path: '/products',
|
||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
} as any).lazy(() => import('./routes/products.lazy').then((d) => d.Route))
|
} as any).lazy(() => import('./routes/products.lazy').then((d) => d.Route))
|
||||||
|
|
||||||
const MarketplacesLazyRoute = MarketplacesLazyImport.update({
|
const MarketplacesLazyRoute = MarketplacesLazyImport.update({
|
||||||
|
id: '/marketplaces',
|
||||||
path: '/marketplaces',
|
path: '/marketplaces',
|
||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
} as any).lazy(() => import('./routes/marketplaces.lazy').then((d) => d.Route))
|
} as any).lazy(() => import('./routes/marketplaces.lazy').then((d) => d.Route))
|
||||||
|
|
||||||
const LoginLazyRoute = LoginLazyImport.update({
|
const LoginLazyRoute = LoginLazyImport.update({
|
||||||
|
id: '/login',
|
||||||
path: '/login',
|
path: '/login',
|
||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
} as any).lazy(() => import('./routes/login.lazy').then((d) => d.Route))
|
} as any).lazy(() => import('./routes/login.lazy').then((d) => d.Route))
|
||||||
|
|
||||||
const LeadsLazyRoute = LeadsLazyImport.update({
|
const LeadsLazyRoute = LeadsLazyImport.update({
|
||||||
|
id: '/leads',
|
||||||
path: '/leads',
|
path: '/leads',
|
||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
} as any).lazy(() => import('./routes/leads.lazy').then((d) => d.Route))
|
} as any).lazy(() => import('./routes/leads.lazy').then((d) => d.Route))
|
||||||
|
|
||||||
const ClientsLazyRoute = ClientsLazyImport.update({
|
const ClientsLazyRoute = ClientsLazyImport.update({
|
||||||
|
id: '/clients',
|
||||||
path: '/clients',
|
path: '/clients',
|
||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
} as any).lazy(() => import('./routes/clients.lazy').then((d) => d.Route))
|
} as any).lazy(() => import('./routes/clients.lazy').then((d) => d.Route))
|
||||||
|
|
||||||
const BarcodeLazyRoute = BarcodeLazyImport.update({
|
const BarcodeLazyRoute = BarcodeLazyImport.update({
|
||||||
|
id: '/barcode',
|
||||||
path: '/barcode',
|
path: '/barcode',
|
||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
} as any).lazy(() => import('./routes/barcode.lazy').then((d) => d.Route))
|
} as any).lazy(() => import('./routes/barcode.lazy').then((d) => d.Route))
|
||||||
|
|
||||||
const AdminLazyRoute = AdminLazyImport.update({
|
const AdminLazyRoute = AdminLazyImport.update({
|
||||||
|
id: '/admin',
|
||||||
path: '/admin',
|
path: '/admin',
|
||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
} as any).lazy(() => import('./routes/admin.lazy').then((d) => d.Route))
|
} as any).lazy(() => import('./routes/admin.lazy').then((d) => d.Route))
|
||||||
|
|
||||||
const IndexLazyRoute = IndexLazyImport.update({
|
const IndexLazyRoute = IndexLazyImport.update({
|
||||||
|
id: '/',
|
||||||
path: '/',
|
path: '/',
|
||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
} as any).lazy(() => import('./routes/index.lazy').then((d) => d.Route))
|
} as any).lazy(() => import('./routes/index.lazy').then((d) => d.Route))
|
||||||
|
|
||||||
const LeadsDealIdRoute = LeadsDealIdImport.update({
|
const LeadsDealIdRoute = LeadsDealIdImport.update({
|
||||||
|
id: '/$dealId',
|
||||||
path: '/$dealId',
|
path: '/$dealId',
|
||||||
getParentRoute: () => LeadsLazyRoute,
|
getParentRoute: () => LeadsLazyRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
|
||||||
const DealsDealIdRoute = DealsDealIdImport.update({
|
const DealsDealIdRoute = DealsDealIdImport.update({
|
||||||
|
id: '/deals/$dealId',
|
||||||
path: '/deals/$dealId',
|
path: '/deals/$dealId',
|
||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
} as any)
|
} as any)
|
||||||
@@ -406,8 +422,6 @@ export const routeTree = rootRoute
|
|||||||
._addFileChildren(rootRouteChildren)
|
._addFileChildren(rootRouteChildren)
|
||||||
._addFileTypes<FileRouteTypes>()
|
._addFileTypes<FileRouteTypes>()
|
||||||
|
|
||||||
/* prettier-ignore-end */
|
|
||||||
|
|
||||||
/* ROUTE_MANIFEST_START
|
/* ROUTE_MANIFEST_START
|
||||||
{
|
{
|
||||||
"routes": {
|
"routes": {
|
||||||
|
|||||||
Reference in New Issue
Block a user