Removed mantine libraries; Removed mandatory authentication

This commit is contained in:
2025-09-22 09:38:21 +09:00
parent c8caec7351
commit 037c0b7cf1
18 changed files with 686 additions and 1069 deletions

View File

@@ -1,15 +1,15 @@
import { Modal, useMantineColorScheme } from "@mantine/core";
import { IconMathMax, IconPlus, IconTableMinus } from "@tabler/icons-react";
import { FuelExpenseDtoHeaders, FuelLimitDtoHeaders } from "../dto/fuel/fuel.dto";
import useSWR from "swr";
import { fetcher } from "../http/axiosInstanceNest";
import { useEffect, useState } from "react";
import { DateInput } from '@mantine/dates'
import { SubmitHandler, useForm } from "react-hook-form";
import { AgGridReact } from "ag-grid-react";
import { AllCommunityModule, ColDef, ModuleRegistry } from 'ag-grid-community'
import { Button, Field, Input, Spinner, Tab, TabList } from "@fluentui/react-components";
import { CalendarStrings, DatePicker, defaultDatePickerStrings } from "@fluentui/react-datepicker-compat"
import { Button, Dialog, DialogSurface, DialogTitle, DialogTrigger, Field, Input, Spinner, Tab, TabList } from "@fluentui/react-components";
import { useAppStore } from "../store/app";
ModuleRegistry.registerModules([AllCommunityModule])
@@ -94,9 +94,7 @@ export default function FuelPage() {
const { isLoading } = useSWR(currentTab.get, () => fetcher(currentTab.get), { revalidateOnFocus: false })
const [openCreateModel, setOpenCreateModal] = useState(false)
const { colorScheme } = useMantineColorScheme()
const { colorScheme } = useAppStore()
useEffect(() => {
if (colorScheme === 'dark') {
@@ -108,8 +106,6 @@ export default function FuelPage() {
return (
<>
<ModalCreate openedCreateModal={openCreateModel} closeCreateModal={() => setOpenCreateModal(false)} currentTab={currentTab} />
<div style={{ display: 'flex', flexDirection: 'column', width: '100%' }}>
<TabList defaultValue={tables[0].value} selectedValue={currentTab.value}>
{tables.map((table, index) => (
@@ -120,9 +116,22 @@ export default function FuelPage() {
</TabList>
<div style={{ display: 'flex', padding: '1rem' }}>
<Button appearance='primary' icon={<IconPlus />} onClick={() => setOpenCreateModal(true)}>
Добавить
</Button>
<Dialog>
<DialogTrigger>
<Button
appearance='primary'
icon={<IconPlus />}
style={{ flexShrink: 0 }}
>
Добавить
</Button>
</DialogTrigger>
<DialogSurface>
<DialogTitle>Добавление объекта</DialogTitle>
<ModalCreate currentTab={currentTab} />
</DialogSurface>
</Dialog>
</div>
{tables.map((table, index) => {
@@ -133,7 +142,7 @@ export default function FuelPage() {
<Spinner />
</div>
:
<>
<div style={{ width: '100%', height: '100%', padding: '1rem' }}>
<AgGridReact
key={index}
//rowData={data}
@@ -148,7 +157,7 @@ export default function FuelPage() {
flex: 1,
}}
/>
</>
</div>
)
}
}
@@ -159,12 +168,8 @@ export default function FuelPage() {
}
const ModalCreate = ({
openedCreateModal,
closeCreateModal,
currentTab
}: {
openedCreateModal: boolean
closeCreateModal: () => void
currentTab: ITableSchema
}) => {
const { register, handleSubmit,
@@ -177,38 +182,72 @@ const ModalCreate = ({
console.log('Values to submit:', values)
}
return (
<Modal withinPortal opened={openedCreateModal} onClose={closeCreateModal}>
<form style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }} onSubmit={handleSubmit(onSubmit)}>
{currentTab.post_include.map((header, index) => {
switch (header.field_type) {
case 'date':
return (
<DateInput label={header.field} />
)
case 'text':
return (
<Field key={index} label={header.field}>
<Input {...register(header.field, {
required: true
})} />
</Field>
)
default:
return (
<Field key={index} label={header.field}>
<Input {...register(header.field, {
required: true
})} />
</Field>
)
}
})}
const localizedStrings: CalendarStrings = {
...defaultDatePickerStrings,
days: [
'Воскресенье',
'Понедельник',
'Вторник',
'Среда',
'Четверг',
'Пятница',
'Суббота'
],
shortDays: ['Вс', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб'],
months: [
"Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Ноябрь", "Декабрь"
],
shortMonths: [
"Янв",
"Фев",
"Мар",
"Апр",
"Май",
"Июн",
"Июл",
"Авг",
"Сен",
"Ноя",
"Дек",
]
}
<Button style={{ marginTop: '2rem' }} appearance="primary" type='submit'>
Добавить
</Button>
</form>
</Modal>
return (
<form style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }} onSubmit={handleSubmit(onSubmit)}>
{currentTab.post_include.map((header, index) => {
switch (header.field_type) {
case 'date':
return (
<Field key={index} label={header.field}>
<DatePicker
strings={localizedStrings}
{...register(header.field, {
required: true
})} />
</Field>
)
case 'text':
return (
<Field key={index} label={header.field}>
<Input {...register(header.field, {
required: true
})} />
</Field>
)
default:
return (
<Field key={index} label={header.field}>
<Input {...register(header.field, {
required: true
})} />
</Field>
)
}
})}
<Button style={{ marginTop: '2rem' }} appearance="primary" type='submit'>
Добавить
</Button>
</form>
)
}

View File

@@ -1,10 +1,10 @@
import { useEffect, useState } from "react"
import createReport, { listCommands } from 'docx-templates'
import { Dropzone, IMAGE_MIME_TYPE } from '@mantine/dropzone'
import { IconFileTypeDocx, IconPlus, IconUpload, IconX } from "@tabler/icons-react"
import { IconPlus, IconX } from "@tabler/icons-react"
import { CommandSummary } from "docx-templates/lib/types"
import { Control, Controller, FieldValues, SubmitHandler, useFieldArray, useForm, UseFormRegister } from "react-hook-form"
import { Button, Field, Input, Text } from "@fluentui/react-components"
import { Button, Field, Input, Text, tokens, useId } from "@fluentui/react-components"
import { ArrowUploadRegular } from "@fluentui/react-icons"
const xslTemplate = `<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
@@ -1062,6 +1062,8 @@ const FormLoop = ({
)
}
const IMAGE_MIME_TYPE = ["image/png", "image/jpeg", "image/jpg", "image/webp"];
const renderCommand = (
control: Control<FieldValues, any>,
register: UseFormRegister<FieldValues>,
@@ -1080,50 +1082,72 @@ const renderCommand = (
}
if (command.type === 'IMAGE') {
const inputId = useId("file-input");
return (
<div style={{ display: 'flex', flexDirection: 'column' }}>
<Text size={200} weight="semibold">{command.code}</Text>
<Controller
key={key}
name={name}
control={control}
render={({ field: { onChange } }) => (
<Dropzone
accept={IMAGE_MIME_TYPE}
maxSize={5 * 1024 ** 2}
onReject={(files) => console.log('rejected files', files)}
onDrop={(files) => {
console.log(files[0])
files[0].arrayBuffer().then(res => {
onChange({
width: 6,
height: 6,
data: new Uint8Array(res),
extension: files[0]?.path?.match(/\.[^.]+$/)?.[0] || ""
})
})
}}
maxFiles={1}
>
<div style={{ display: 'flex', justifyContent: 'center', gap: '2rem', minHeight: '220px', pointerEvents: 'none' }}>
<Dropzone.Accept>
<IconUpload size={52} color="var(--mantine-color-blue-6)" stroke={1.5} />
</Dropzone.Accept>
<Dropzone.Reject>
<IconX size={52} color="var(--mantine-color-red-6)" stroke={1.5} />
</Dropzone.Reject>
<Dropzone.Idle>
<IconFileTypeDocx size={52} color="var(--mantine-color-dimmed)" stroke={1.5} />
</Dropzone.Idle>
render={({ field: { onChange } }) => {
const handleFiles = (files: FileList | null) => {
if (!files || files.length === 0) return;
const file = files[0];
if (!IMAGE_MIME_TYPE.includes(file.type)) {
console.log("Rejected file:", file);
return;
}
<div>
<Text size={300}>
Перетащите файлы сюда или нажмите, чтобы выбрать их
</Text>
</div>
file.arrayBuffer().then((res) => {
onChange({
width: 6,
height: 6,
data: new Uint8Array(res),
extension: file.name.match(/\.[^.]+$/)?.[0] || "",
});
});
};
const handleDrop = (e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault();
handleFiles(e.dataTransfer.files);
};
return (
<div
onDragOver={(e) => e.preventDefault()}
onDrop={handleDrop}
style={{
border: `2px dashed ${tokens.colorNeutralStroke1}`,
borderRadius: tokens.borderRadiusLarge,
minHeight: "220px",
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
gap: "1rem",
padding: "1rem",
textAlign: "center",
cursor: "pointer",
}}
onClick={() => document.getElementById(inputId)?.click()}
>
<input
id={inputId}
type="file"
accept={IMAGE_MIME_TYPE.join(",")}
style={{ display: "none" }}
onChange={(e) => handleFiles(e.target.files)}
/>
<ArrowUploadRegular fontSize={40} color={tokens.colorBrandForeground1} />
<Text size={300}>
Перетащите изображение сюда или нажмите, чтобы выбрать
</Text>
</div>
</Dropzone>
)}
);
}}
/>
</div>
)

View File

@@ -2,7 +2,7 @@ import { useRoles } from '../hooks/swrHooks'
import { CreateField } from '../interfaces/create'
import RoleService from '../services/RoleService'
import CustomTable from '../components/CustomTable'
import { Spinner } from '@fluentui/react-components'
import { Link, Spinner } from '@fluentui/react-components'
export default function Roles() {
const { roles, isError, isLoading } = useRoles()
@@ -12,8 +12,37 @@ export default function Roles() {
{ key: 'description', headerName: 'Описание', type: 'string', required: false, defaultValue: '' },
]
if (isError) return <div>Произошла ошибка при получении данных.</div>
if (isLoading) return <Spinner />
const handleError = (error: any) => {
if (error?.response?.status === 401) {
return (
<Link href="/auth/signin">
Войдите, чтобы продолжить
</Link>
)
} else {
return "Произошла ошибка при получении данных."
}
}
if (isError) return (
<div style={{ padding: '1rem' }}>
{handleError(isError)}
</div>
)
if (isLoading)
return (
<div style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: '100%',
height: '100%',
padding: '1rem',
}}>
<Spinner />
</div>
)
return (
<div style={{

View File

@@ -4,7 +4,7 @@ import { useEffect, useState } from "react"
import { CreateField } from "../interfaces/create"
import UserService from "../services/UserService"
import CustomTable from "../components/CustomTable"
import { Spinner } from "@fluentui/react-components"
import { Link, Spinner } from "@fluentui/react-components"
import { IUser } from "../interfaces/user"
export default function Users() {
@@ -37,15 +37,34 @@ export default function Users() {
{ key: 'password', headerName: 'Пароль', type: 'string', required: true, defaultValue: '' },
]
const handleError = (error: any) => {
if (error?.response?.status === 401) {
return (
<Link href="/auth/signin">
Войдите, чтобы продолжить
</Link>
)
} else {
return "Произошла ошибка при получении данных."
}
}
if (isError) return (
<div>
Произошла ошибка при получении данных.
<div style={{ padding: '1rem' }}>
{handleError(isError)}
</div>
)
if (isLoading) {
return (
<div>
<div style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: '100%',
height: '100%',
padding: '1rem',
}}>
<Spinner />
</div>
)

View File

@@ -100,7 +100,8 @@ const SignIn = () => {
{pages.find(page => page.path === '/auth/signup')?.enabled &&
<Button as='a' href='/auth/signup' type="button" appearance='subtle'>
Регистрация
</Button>}
</Button>
}
</div>
</form>
</div>