sight edit update

This commit is contained in:
2025-04-25 05:23:07 +03:00
parent 463c593a0e
commit 9927c0afd6
22 changed files with 3011 additions and 1742 deletions

View File

@ -1,181 +1,246 @@
import DarkModeOutlined from '@mui/icons-material/DarkModeOutlined'
import LightModeOutlined from '@mui/icons-material/LightModeOutlined'
import AppBar from '@mui/material/AppBar'
import Avatar from '@mui/material/Avatar'
import IconButton from '@mui/material/IconButton'
import Stack from '@mui/material/Stack'
import Toolbar from '@mui/material/Toolbar'
import Typography from '@mui/material/Typography'
import {useGetIdentity, usePermissions, useWarnAboutChange} from '@refinedev/core'
import {HamburgerMenu, RefineThemedLayoutV2HeaderProps} from '@refinedev/mui'
import React, {useContext, useEffect} from 'react'
import {ColorModeContext} from '../../contexts/color-mode'
import Cookies from 'js-cookie'
import {useTranslation} from 'react-i18next'
import {Button} from '@mui/material'
import {useNavigate} from 'react-router'
import DarkModeOutlined from "@mui/icons-material/DarkModeOutlined";
import LightModeOutlined from "@mui/icons-material/LightModeOutlined";
import AppBar from "@mui/material/AppBar";
import Avatar from "@mui/material/Avatar";
import IconButton from "@mui/material/IconButton";
import Stack from "@mui/material/Stack";
import Toolbar from "@mui/material/Toolbar";
import Typography from "@mui/material/Typography";
import {
useGetIdentity,
useList,
usePermissions,
useWarnAboutChange,
} from "@refinedev/core";
import { HamburgerMenu, RefineThemedLayoutV2HeaderProps } from "@refinedev/mui";
import React, { useContext, useEffect, useState } from "react";
import { ColorModeContext } from "../../contexts/color-mode";
import Cookies from "js-cookie";
import { useTranslation } from "react-i18next";
import {
Button,
Select,
MenuItem,
InputLabel,
FormControl,
SelectChangeEvent,
} from "@mui/material";
import { useNavigate } from "react-router";
import { cityStore } from "../../store/CityStore";
import { observer } from "mobx-react-lite";
type IUser = {
id: number
name: string
avatar: string
is_admin: boolean
}
id: number;
name: string;
avatar: string;
is_admin: boolean;
};
export const Header: React.FC<RefineThemedLayoutV2HeaderProps> = ({sticky = true}) => {
const {mode, setMode} = useContext(ColorModeContext)
const {data: user} = useGetIdentity<IUser>()
const {data: permissions} = usePermissions<string[]>()
const isAdmin = permissions?.includes('admin')
const {i18n} = useTranslation()
const {setWarnWhen, warnWhen} = useWarnAboutChange()
export const Header: React.FC<RefineThemedLayoutV2HeaderProps> = observer(
({ sticky }) => {
const { city_id, setCityIdAction } = cityStore;
const { data: cities } = useList({
resource: "city",
});
const navigate = useNavigate()
const { mode, setMode } = useContext(ColorModeContext);
const { data: user } = useGetIdentity<IUser>();
const { data: permissions } = usePermissions<string[]>();
const isAdmin = permissions?.includes("admin");
const { i18n } = useTranslation();
const { setWarnWhen, warnWhen } = useWarnAboutChange();
const navigate = useNavigate();
const handleLanguageChange = async (lang: string) => {
// console.log('Language change requested:', lang)
// console.log('Current warnWhen state:', warnWhen)
const handleChange = (event: SelectChangeEvent<string>) => {
setCityIdAction(event.target.value);
};
const form = document.querySelector('form')
const inputs = form?.querySelectorAll<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>('input, textarea, select')
const saveButton = document.querySelector('.refine-save-button') as HTMLButtonElement
const handleLanguageChange = async (lang: string) => {
// console.log('Language change requested:', lang)
// console.log('Current warnWhen state:', warnWhen)
// Сохраняем текущий URL перед любыми действиями
const currentLocation = window.location.pathname + window.location.search
const form = document.querySelector("form");
const inputs = form?.querySelectorAll<
HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement
>("input, textarea, select");
const saveButton = document.querySelector(
".refine-save-button"
) as HTMLButtonElement;
if (form && saveButton) {
const hasChanges = Array.from(inputs || []).some((input) => {
if (input instanceof HTMLInputElement || input instanceof HTMLTextAreaElement) {
return input.value !== input.defaultValue
}
if (input instanceof HTMLSelectElement) {
return input.value !== input.options[input.selectedIndex].defaultSelected.toString()
}
return false
})
// Сохраняем текущий URL перед любыми действиями
const currentLocation = window.location.pathname + window.location.search;
if (hasChanges || warnWhen) {
try {
// console.log('Attempting to save changes...')
setWarnWhen(false)
saveButton.click()
// console.log('Save button clicked')
if (form && saveButton) {
const hasChanges = Array.from(inputs || []).some((input) => {
if (
input instanceof HTMLInputElement ||
input instanceof HTMLTextAreaElement
) {
return input.value !== input.defaultValue;
}
if (input instanceof HTMLSelectElement) {
return (
input.value !==
input.options[input.selectedIndex].defaultSelected.toString()
);
}
return false;
});
await new Promise((resolve) => setTimeout(resolve, 1000))
if (hasChanges || warnWhen) {
try {
// console.log('Attempting to save changes...')
setWarnWhen(false);
saveButton.click();
// console.log('Save button clicked')
// После сохранения меняем язык и возвращаемся на ту же страницу
Cookies.set('lang', lang)
i18n.changeLanguage(lang)
navigate(currentLocation)
return
} catch (error) {
console.error('Failed to save form:', error)
setWarnWhen(true)
return
await new Promise((resolve) => setTimeout(resolve, 1000));
// После сохранения меняем язык и возвращаемся на ту же страницу
Cookies.set("lang", lang);
i18n.changeLanguage(lang);
navigate(currentLocation);
return;
} catch (error) {
console.error("Failed to save form:", error);
setWarnWhen(true);
return;
}
}
}
}
// Если нет формы или изменений, просто меняем язык
// console.log('Setting language cookie:', lang)
Cookies.set('lang', lang)
// Если нет формы или изменений, просто меняем язык
// console.log('Setting language cookie:', lang)
Cookies.set("lang", lang);
// console.log('Changing i18n language')
i18n.changeLanguage(lang)
// console.log('Changing i18n language')
i18n.changeLanguage(lang);
// Используем текущий URL для навигации
navigate(0)
}
// Используем текущий URL для навигации
navigate(0);
};
useEffect(() => {
const savedLang = Cookies.get('lang') || 'ru'
i18n.changeLanguage(savedLang)
}, [i18n])
useEffect(() => {
const savedLang = Cookies.get("lang") || "ru";
i18n.changeLanguage(savedLang);
}, [i18n]);
return (
<AppBar position={sticky ? "sticky" : "relative"}>
<Toolbar>
<Stack
direction="row"
width="100%"
justifyContent="flex-end"
alignItems="center"
>
<HamburgerMenu />
return (
<AppBar position={sticky ? 'sticky' : 'relative'}>
<Toolbar>
<Stack direction="row" width="100%" justifyContent="flex-end" alignItems="center">
<HamburgerMenu />
<Stack direction="row" width="100%" justifyContent="flex-end" alignItems="center" spacing={2}>
<Stack
direction="row"
spacing={1}
sx={{
backgroundColor: 'background.paper',
padding: '4px',
borderRadius: '4px',
}}
width="100%"
justifyContent="flex-end"
alignItems="center"
spacing={2}
>
{['ru', 'en', 'zh'].map((lang) => (
<Button
key={lang}
onClick={() => handleLanguageChange(lang)}
variant={i18n.language === lang ? 'contained' : 'outlined'}
size="small"
sx={{
minWidth: '30px',
padding: '2px 0px',
textTransform: 'uppercase',
}}
>
{lang}
</Button>
))}
</Stack>
<IconButton
color="inherit"
onClick={() => {
setMode()
}}
sx={{
marginRight: '2px',
}}
>
{mode === 'dark' ? <LightModeOutlined /> : <DarkModeOutlined />}
</IconButton>
{(user?.avatar || user?.name) && (
<Stack direction="row" gap="16px" alignItems="center" justifyContent="center">
{user?.name && (
<Stack direction="column" alignItems="start" gap="0px">
<Typography
sx={{
display: {
xs: 'none',
sm: 'inline-block',
},
}}
variant="subtitle2"
>
{user?.name}
</Typography>
<Typography
sx={{
display: {
xs: 'none',
sm: 'inline-block',
},
backgroundColor: 'primary.main',
color: 'rgba(255, 255, 255, 0.7)',
padding: '1px 4px',
borderRadius: 1,
fontSize: '0.6rem',
}}
variant="subtitle2"
>
{isAdmin ? 'Администратор' : 'Пользователь'}
</Typography>
</Stack>
<FormControl variant="standard" sx={{ width: "min-content" }}>
{city_id && cities && (
<Select
defaultValue={city_id}
value={city_id}
onChange={handleChange}
>
{cities.data?.map((city) => (
<MenuItem value={String(city.id)} key={city.id}>
{city.name}
</MenuItem>
))}
</Select>
)}
<Avatar src={user?.avatar} alt={user?.name} />
</FormControl>
<Stack
direction="row"
spacing={1}
sx={{
backgroundColor: "background.paper",
padding: "4px",
borderRadius: "4px",
}}
>
{["ru", "en", "zh"].map((lang) => (
<Button
key={lang}
onClick={() => handleLanguageChange(lang)}
variant={i18n.language === lang ? "contained" : "outlined"}
size="small"
sx={{
minWidth: "30px",
padding: "2px 0px",
textTransform: "uppercase",
}}
>
{lang}
</Button>
))}
</Stack>
)}
<IconButton
color="inherit"
onClick={() => {
setMode();
}}
sx={{
marginRight: "2px",
}}
>
{mode === "dark" ? <LightModeOutlined /> : <DarkModeOutlined />}
</IconButton>
{(user?.avatar || user?.name) && (
<Stack
direction="row"
gap="16px"
alignItems="center"
justifyContent="center"
>
{user?.name && (
<Stack direction="column" alignItems="start" gap="0px">
<Typography
sx={{
display: {
xs: "none",
sm: "inline-block",
},
}}
variant="subtitle2"
>
{user?.name}
</Typography>
<Typography
sx={{
display: {
xs: "none",
sm: "inline-block",
},
backgroundColor: "primary.main",
color: "rgba(255, 255, 255, 0.7)",
padding: "1px 4px",
borderRadius: 1,
fontSize: "0.6rem",
}}
variant="subtitle2"
>
{isAdmin ? "Администратор" : "Пользователь"}
</Typography>
</Stack>
)}
<Avatar src={user?.avatar} alt={user?.name} />
</Stack>
)}
</Stack>
</Stack>
</Stack>
</Toolbar>
</AppBar>
)
}
</Toolbar>
</AppBar>
);
}
);