This commit is contained in:
Nastya 2023-08-07 15:57:44 +00:00
parent 1df8502813
commit 24399db30b
24 changed files with 1670 additions and 788 deletions

11
cypress.config.ts Normal file

@ -0,0 +1,11 @@
import { defineConfig } from "cypress";
export default defineConfig({
e2e: {
viewportWidth: 1200,
viewportHeight: 800,
fixturesFolder: "tests/e2e/fixtures",
supportFile: false,
defaultCommandTimeout: 100,
},
});

125
cypress/e2e/access.cy.ts Normal file

@ -0,0 +1,125 @@
describe("Форма Входа", () => {
beforeEach(() => {
cy.visit("http://localhost:3000");
cy.wait(1000);
cy.contains("Личный кабинет").click();
});
it("должна успешно входить с правильными учетными данными", () => {
const login = "valid_user@example.com";
const password = "valid_password";
cy.get("#login").type(login);
cy.get("#password").type(password);
cy.get('button[type="submit"]').click();
cy.wait(2000);
cy.url().should("include", "http://localhost:3000/tariffs");
});
it("должна отображать два сообщение об ошибке при отсутствии полей", () => {
cy.get('button[type="submit"]').click();
cy.wait(2000);
cy.get("#password-helper-text").should("contain", "Поле обязательно");
cy.get("#login-helper-text").should("contain", "Поле обязательно");
});
it("должна отображать сообщение об ошибке при отсутствии пароля", () => {
cy.get("#login").type("valid_email@example.com");
cy.get('button[type="submit"]').click();
cy.get("#password-helper-text").should("contain", "Поле обязательно");
});
it("должна отображать сообщение об ошибке при отсутствии Логина", () => {
cy.get("#password").type("valid_password");
cy.get('button[type="submit"]').click();
cy.get("#login-helper-text").should("contain", "Поле обязательно");
});
});
describe("Форма регистрации", () => {
beforeEach(() => {
cy.visit("http://localhost:3000");
cy.wait(1000);
cy.contains("Личный кабинет").click();
cy.contains("Регистрация").click();
});
it("должна регистрировать нового пользователя с правильными данными", () => {
const login = Cypress._.random(1000) + "@example.com";
const password = "valid_password";
cy.get("#login").type(login);
cy.get("#password").type(password);
cy.get("#repeatPassword").type(password);
cy.get('button[type="submit"]').click();
cy.wait(5000);
cy.url().should("include", "http://localhost:3000/tariffs");
});
it("должна отображать ошибку при отсутсвии логина", () => {
cy.get("#password").type("valid_password");
cy.get("#repeatPassword").type("valid_password");
cy.get('button[type="submit"]').click();
cy.get("#login-helper-text").should("contain", "Поле обязательно");
});
it("должна отображать ошибку при отсутствии пароля", () => {
cy.get("#login").type("valid_login");
cy.get('button[type="submit"]').click();
cy.get("#password-helper-text").should("contain", "Поле обязательно");
});
it("должна отображать ошибку при отсутствии поля Повторения пароля", () => {
cy.get("#login").type("valid_login");
cy.get("#password").type("valid_password");
cy.get('button[type="submit"]').click();
cy.get("#repeatPassword-helper-text").should("contain", "Повторите пароль");
});
it("должна отображать ошибку при некоректном пароле", () => {
cy.get("#login").type("valid_log");
cy.get("#password").type("valid@12_-_@@password");
cy.get('button[type="submit"]').click();
cy.get("#password-helper-text").should("contain", "Некорректные символы");
cy.get("#repeatPassword-helper-text").should("contain", "Повторите пароль");
});
it("должна отображать ошибку при несовпадении паролей", () => {
cy.get("#login").type("valid_login");
cy.get("#password").type("valid_password");
cy.get("#repeatPassword").type("invalidPassword");
cy.get('button[type="submit"]').click();
cy.get("#repeatPassword-helper-text").should("contain", "Пароли не совпадают");
});
it("попытка отправки запроса при уже зарегистрированном пользователе", () => {
const login = "valid_user@example.com";
const password = "valid_password";
cy.get("#login").type(login);
cy.get("#password").type(password);
cy.get("#repeatPassword").type(password);
cy.get('button[type="submit"]').click();
cy.wait(5000);
cy.contains("user with this login is exist");
});
});

@ -7,7 +7,9 @@
"build": "craco build",
"test": "craco test --env=node --transformIgnorePatterns \"node_modules/(?!@frontend)/\"",
"test:cart": "craco test src/utils/calcCart --transformIgnorePatterns \"node_modules/(?!@frontend)/\"",
"eject": "craco eject"
"eject": "craco eject",
"test:cypress": "start-server-and-test start http://localhost:3000 cypress",
"cypress": "cypress open"
},
"dependencies": {
"@emotion/react": "^11.10.5",
@ -19,6 +21,7 @@
"axios": "^1.4.0",
"buffer": "^6.0.3",
"classnames": "^2.3.2",
"cypress": "^12.17.3",
"formik": "^2.2.9",
"immer": "^10.0.2",
"isomorphic-fetch": "^3.0.0",

@ -51,9 +51,7 @@ export default function Drawers() {
(state) => state.summaryPriceAfterDiscountsMap
);
const userAccount = useUserStore((state) => state.userAccount);
const { tickets, ticketCount, apiPage, ticketsPerPage } = useTicketStore(
(state) => state
);
const { tickets, apiPage, ticketsPerPage } = useTicketStore((state) => state);
useTickets({
url: "https://hub.pena.digital/heruvym/getTickets",
@ -75,6 +73,10 @@ export default function Drawers() {
0
);
const notificationsCount = tickets.filter(
({ user, top_message }) => user !== top_message.user_id
).length;
const totalPriceBeforeDiscounts = cart.priceBeforeDiscounts + basePrice;
const totalPriceAfterDiscounts = cart.priceAfterDiscounts + discountedPrice;
@ -119,10 +121,10 @@ export default function Drawers() {
}}
>
<Badge
badgeContent={ticketCount}
badgeContent={notificationsCount}
sx={{
"& .MuiBadge-badge": {
display: ticketCount ? "flex" : "none",
display: notificationsCount ? "flex" : "none",
color: "#FFFFFF",
background: theme.palette.brightPurple.main,
transform: "scale(0.8) translate(50%, -50%)",
@ -136,12 +138,13 @@ export default function Drawers() {
</Badge>
</IconButton>
<NotificationsModal
open={openNotificationsModal}
open={notificationsCount ? openNotificationsModal : false}
setOpen={setOpenNotificationsModal}
anchorElement={bellRef.current}
notifications={tickets.map((ticket) => ({
text: "У вас новое сообщение от техподдержки",
date: new Date(ticket.updated_at).toLocaleDateString(),
url: `/support/${ticket.id}`,
watched: ticket.user === ticket.top_message.user_id,
}))}
/>

@ -12,6 +12,7 @@ import {
import { useUserStore } from "@root/stores/user";
import { currencyFormatter } from "@root/utils/currencyFormatter";
import { cardShadow } from "@root/utils/themes/shadow";
import CustomAvatar from "./Avatar";
@ -45,6 +46,7 @@ export default function DialogMenu({ handleClose }: DialogMenuProps) {
const [activeSubMenuIndex, setActiveSubMenuIndex] = useState<number>(-1);
const theme = useTheme();
const location = useLocation();
const isTablet = useMediaQuery(theme.breakpoints.down(900));
const isMobile = useMediaQuery(theme.breakpoints.down(600));
const user = useUserStore((state) => state.user);
const cash = useUserStore((state) => state.userAccount?.wallet.cash) ?? 0;
@ -118,12 +120,13 @@ export default function DialogMenu({ handleClose }: DialogMenuProps) {
sx={{
backgroundColor: theme.palette.background.paper,
width: "100%",
boxShadow: !isTablet ? cardShadow : null,
}}
>
{index === activeSubMenuIndex &&
subMenu.map(({ name, url }) => (
<Link
key={url}
key={name + url}
style={{
paddingLeft: "30px",
display: "block",

@ -1,4 +1,4 @@
import { useMediaQuery, useTheme } from "@mui/material";
import { Box, useMediaQuery, useTheme } from "@mui/material";
import NavbarCollapsed from "./NavbarCollapsed";
import NavbarFull from "./NavbarFull";
@ -14,12 +14,17 @@ export default function Navbar({ isLoggedIn, children }: Props) {
const upMd = useMediaQuery(theme.breakpoints.up("md"));
return (
<>
<Box
sx={{
paddingTop: upMd ? "80px" : 0,
width: "100%",
}}
>
{upMd ? (
<NavbarFull isLoggedIn={isLoggedIn}>{children}</NavbarFull>
) : (
<NavbarCollapsed isLoggedIn={isLoggedIn}>{children}</NavbarCollapsed>
)}
</>
</Box>
);
}

@ -34,9 +34,7 @@ export default function NavbarCollapsed({ isLoggedIn, children }: Props) {
useState<boolean>(false);
const bellRef = useRef<HTMLButtonElement | null>(null);
const userAccount = useUserStore((state) => state.userAccount);
const { ticketCount, tickets, apiPage, ticketsPerPage } = useTicketStore(
(state) => state
);
const { tickets, apiPage, ticketsPerPage } = useTicketStore((state) => state);
useTickets({
url: "https://hub.pena.digital/heruvym/getTickets",
@ -55,6 +53,10 @@ export default function NavbarCollapsed({ isLoggedIn, children }: Props) {
setOpen(false);
};
const notificationsCount = tickets.filter(
({ user, top_message }) => user !== top_message.user_id
).length;
useEffect(() => {
if (open) {
document.body.style.overflow = "hidden";
@ -71,18 +73,23 @@ export default function NavbarCollapsed({ isLoggedIn, children }: Props) {
maxWidth="lg"
outerContainerSx={{
backgroundColor: theme.palette.navbarbg.main,
position: "sticky",
top: 0,
}}
sx={{ height: "51px", padding: "0" }}
>
<Box sx={{ height: "100%" }}>
<Box
sx={{
zIndex: 2,
position: "fixed",
top: 0,
left: 0,
width: "100%",
display: "flex",
columnGap: "10px",
alignItems: "center",
height: "100%",
height: "51px",
padding: "0 18px",
background: "#FFFFFF",
}}
>
<IconButton
@ -158,10 +165,10 @@ export default function NavbarCollapsed({ isLoggedIn, children }: Props) {
}}
>
<Badge
badgeContent={ticketCount}
badgeContent={notificationsCount}
sx={{
"& .MuiBadge-badge": {
display: ticketCount ? "flex" : "none",
display: notificationsCount ? "flex" : "none",
color: "#FFFFFF",
background: theme.palette.brightPurple.main,
transform: "scale(0.7) translate(50%, -50%)",
@ -175,12 +182,13 @@ export default function NavbarCollapsed({ isLoggedIn, children }: Props) {
</Badge>
</IconButton>
<NotificationsModal
open={openNotificationsModal}
open={notificationsCount ? openNotificationsModal : false}
setOpen={setOpenNotificationsModal}
anchorElement={bellRef.current}
notifications={tickets.map((ticket) => ({
text: "У вас новое сообщение от техподдержки",
date: new Date(ticket.updated_at).toLocaleDateString(),
url: `/support/${ticket.id}`,
watched: ticket.user === ticket.top_message.user_id,
}))}
/>
@ -188,6 +196,7 @@ export default function NavbarCollapsed({ isLoggedIn, children }: Props) {
<PenaLogo width={100} />
</Link>
</Box>
</Box>
<Box sx={{ display: "flex", overflow: open ? "hidden" : "unset" }}>
<Drawer
sx={{
@ -195,10 +204,11 @@ export default function NavbarCollapsed({ isLoggedIn, children }: Props) {
position: "relative",
zIndex: open ? "none" : "-1",
"& .MuiDrawer-paper": {
position: "absolute",
position: "fixed",
top: "0",
width: 210,
height: "100%",
marginTop: "51px",
},
}}
variant="persistent"

@ -58,6 +58,8 @@ export default function NavbarFull({ isLoggedIn, children }: Props) {
disableGutters
maxWidth={false}
sx={{
position: "fixed",
top: "0",
px: "16px",
display: "flex",
height: "80px",

@ -3,18 +3,14 @@ import { TransitionProps } from "@mui/material/transitions";
import logotip from "../../assets/Icons/logoPenaHab.svg";
import logotipBlack from "../../assets/Icons/black_logo_PenaHab.svg";
import CustomAvatar from "./Avatar";
import CloseIcon from "../icons/CloseIcons";
import React from "react";
import {
AppBar,
Box,
Button,
Dialog,
IconButton,
List,
ListItem,
Slide,
Toolbar,
Typography,
useMediaQuery,
useTheme,
@ -55,45 +51,44 @@ interface DialogMenuProps {
export default function DialogMenu({ open, handleClose }: DialogMenuProps) {
const theme = useTheme();
const location = useLocation();
const isMobile = useMediaQuery(theme.breakpoints.down(600));
const isTablet = useMediaQuery(theme.breakpoints.down(900));
const user = useUserStore((state) => state.user);
const cash = useUserStore(state => state.userAccount?.wallet.cash) ?? 0;
const cash = useUserStore((state) => state.userAccount?.wallet.cash) ?? 0;
return (
<Dialog
fullScreen
sx={{ width: isMobile ? "100%" : "320px", ml: "auto", height: "100%" }}
sx={{
width: isTablet ? "100%" : "320px",
ml: "auto",
mt: "50px",
height: "100%",
".MuiBackdrop-root.MuiModal-backdrop": {
background: "transparent",
},
".MuiPaper-root.MuiPaper-rounded": {
background: "#333647",
},
}}
open={open}
onClose={handleClose}
TransitionComponent={Transition}
>
<AppBar
<List
sx={{
position: "relative",
background: location.pathname === "/" ? "#333647" : "#FFFFFF",
boxShadow: "none",
height: isMobile ? "66px" : "100px",
height: "100vh",
p: "0",
paddingTop: "20px",
}}
>
<Toolbar
<ListItem
sx={{
display: "flex",
justifyContent: "space-between",
svg: { color: "#000000" },
pl: "40px",
flexDirection: "column",
alignItems: isTablet ? "start" : "end",
}}
>
{isMobile && (
<Box sx={{ mt: "6px" }}>
<img src={location.pathname === "/" ? logotip : logotipBlack} alt="icon" />
</Box>
)}
<IconButton sx={{ ml: "auto" }} edge="start" color="inherit" onClick={handleClose} aria-label="close">
<CloseIcon />
</IconButton>
</Toolbar>
</AppBar>
<List sx={{ background: location.pathname === "/" ? "#333647" : "#FFFFFF", height: "100vh", p: "0" }}>
<ListItem sx={{ pl: "40px", flexDirection: "column", alignItems: isMobile ? "start" : "end" }}>
{arrayMenu.map(({ name, url }, index) => (
<Button
key={index}
@ -105,7 +100,12 @@ export default function DialogMenu({ open, handleClose }: DialogMenuProps) {
variant="text"
sx={{
fontWeight: "500",
color: location.pathname === url ? "#7E2AEA" : location.pathname === "/" ? "white" : "black",
color:
location.pathname === url
? "#7E2AEA"
: location.pathname === "/"
? "white"
: "black",
height: "20px",
textTransform: "none",
marginBottom: "25px",
@ -120,7 +120,7 @@ export default function DialogMenu({ open, handleClose }: DialogMenuProps) {
</Button>
))}
</ListItem>
{isMobile ? (
{isTablet ? (
location.pathname === "/" ? (
<Button
component={Link}
@ -166,7 +166,10 @@ export default function DialogMenu({ open, handleClose }: DialogMenuProps) {
>
Мой баланс
</Typography>
<Typography variant="body2" color={theme.palette.brightPurple.main}>
<Typography
variant="body2"
color={theme.palette.brightPurple.main}
>
{currencyFormatter.format(cash / 100)}
</Typography>
</Box>
@ -201,7 +204,10 @@ export default function DialogMenu({ open, handleClose }: DialogMenuProps) {
bottom: "60px",
}}
>
<img src={location.pathname === "/" ? logotip : logotipBlack} alt="icon" />
<img
src={location.pathname === "/" ? logotip : logotipBlack}
alt="icon"
/>
</Box>
</>
)}

@ -1,12 +1,12 @@
import { useState } from "react";
import { IconButton, useTheme } from "@mui/material";
import MenuIcon from "@mui/icons-material/Menu";
import { Link } from "react-router-dom";
import SectionWrapper from "../SectionWrapper";
import PenaLogo from "../PenaLogo";
import DialogMenu from "./DialogMenu";
import { Link } from "react-router-dom";
interface Props {
isLoggedIn: boolean;
@ -30,11 +30,10 @@ export default function NavbarCollapsed({ isLoggedIn }: Props) {
component="nav"
maxWidth="lg"
outerContainerSx={{
position: "fixed",
top: "0",
backgroundColor: theme.palette.navbarbg.main,
position: "sticky",
top: 0,
zIndex: 1,
// borderBottom: "1px solid #E3E3E3",
borderBottom: "1px solid #E3E3E3",
}}
sx={{
height: "51px",
@ -44,9 +43,14 @@ export default function NavbarCollapsed({ isLoggedIn }: Props) {
alignItems: "center",
}}
>
<Link to="/"><PenaLogo width={100} /></Link>
<Link to="/">
<PenaLogo width={100} />
</Link>
<IconButton onClick={handleClickOpen} sx={{ p: 0, width: "30px", color: theme.palette.primary.main }}>
<IconButton
onClick={handleClickOpen}
sx={{ p: 0, width: "30px", color: theme.palette.primary.main }}
>
<MenuIcon sx={{ height: "30px", width: "30px" }} />
</IconButton>
<DialogMenu open={open} handleClose={handleClose} />

@ -1,5 +1,12 @@
import { Link, useLocation, useNavigate } from "react-router-dom";
import { Box, Button, Container, IconButton, Typography, useTheme } from "@mui/material";
import {
Box,
Button,
Container,
IconButton,
Typography,
useTheme,
} from "@mui/material";
import SectionWrapper from "../SectionWrapper";
import LogoutIcon from "../icons/LogoutIcon";
import WalletIcon from "../icons/WalletIcon";
@ -23,7 +30,7 @@ export default function NavbarFull({ isLoggedIn }: Props) {
const location = useLocation();
const navigate = useNavigate();
const user = useUserStore((state) => state.user);
const cash = useUserStore(state => state.userAccount?.wallet.cash) ?? 0;
const cash = useUserStore((state) => state.userAccount?.wallet.cash) ?? 0;
async function handleLogoutClick() {
try {
@ -53,7 +60,9 @@ export default function NavbarFull({ isLoggedIn }: Props) {
borderBottom: "1px solid #E3E3E3",
}}
>
<Link to="/"><PenaLogo width={124} /></Link>
<Link to="/">
<PenaLogo width={124} />
</Link>
<Menu />
<Box
sx={{
@ -85,7 +94,13 @@ export default function NavbarFull({ isLoggedIn }: Props) {
<CustomAvatar />
<IconButton
onClick={handleLogoutClick}
sx={{ ml: "20px", bgcolor: "#F2F3F7", borderRadius: "6px", height: "36px", width: "36px" }}
sx={{
ml: "20px",
bgcolor: "#F2F3F7",
borderRadius: "6px",
height: "36px",
width: "36px",
}}
>
<LogoutIcon />
</IconButton>
@ -97,6 +112,8 @@ export default function NavbarFull({ isLoggedIn }: Props) {
component="nav"
maxWidth="lg"
outerContainerSx={{
position: "fixed",
top: "0",
backgroundColor: theme.palette.lightPurple.main,
borderBottom: "1px solid #E3E3E3",
}}

@ -6,10 +6,12 @@ import {
useTheme,
useMediaQuery,
} from "@mui/material";
import { Link } from "react-router-dom";
type Notification = {
text: string;
date: string;
url: string;
watched?: boolean;
};
@ -59,8 +61,17 @@ export const NotificationsModal = ({
}}
>
<List sx={{ width: "100%", padding: "5px" }}>
{notifications.map(({ text, date, watched = true }) => (
{notifications.map(({ text, date, url, watched = true }) => (
<Link
to={url}
onClick={() => setOpen(false)}
style={{
textDecoration: "none",
color: "inherit",
}}
>
<ListItem
key={text + date}
sx={{
display: "flex",
alignItems: isMobile ? "normal" : "center",
@ -111,6 +122,7 @@ export const NotificationsModal = ({
{date}
</Typography>
</ListItem>
</Link>
))}
</List>
</Popover>

@ -39,7 +39,7 @@ export const Select = ({
<Box>
<Box
sx={{
zIndex: 1500,
zIndex: 1,
position: "relative",
width: "100%",
height: "56px",
@ -81,6 +81,7 @@ export const Select = ({
<MuiSelect
ref={ref}
className="select"
value=""
open={opened}
MenuProps={{ disablePortal: true }}
sx={{ width: "100%" }}

@ -26,3 +26,7 @@
.MuiInputBase-root.MuiOutlinedInput-root .MuiSelect-icon {
display: none;
}
.MuiMenu-root.MuiModal-root {
z-index: 0;
}

@ -22,9 +22,7 @@ interface Props {
color?: string;
FormInputSx?: SxProps<Theme>;
TextfieldProps: TextFieldProps;
onChange: (
e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>
) => void;
onChange: (e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => void;
}
export default function PasswordInput({
@ -46,17 +44,13 @@ export default function PasswordInput({
: { ...theme.typography.body1, fontWeight: 500 }
: theme.typography.body2;
const placeholderFont = upMd
? undefined
: { fontWeight: 400, fontSize: "16px", lineHeight: "19px" };
const placeholderFont = upMd ? undefined : { fontWeight: 400, fontSize: "16px", lineHeight: "19px" };
const [showPassword, setShowPassword] = React.useState(false);
const handleClickShowPassword = () => setShowPassword((show) => !show);
const handleMouseDownPassword = (
event: React.MouseEvent<HTMLButtonElement>
) => {
const handleMouseDownPassword = (event: React.MouseEvent<HTMLButtonElement>) => {
event.preventDefault();
};

@ -20,6 +20,7 @@ export default function Landing({ templaterOnly = false }: Props) {
<Box
sx={{
position: "relative",
paddingTop: "80px",
}}
>
<Navbar isLoggedIn={false} />

@ -46,6 +46,10 @@
right: -5px;
}
.slider .slick-arrow::before {
display: none;
}
.slider .slick-dots {
bottom: -15px;
}

@ -12,19 +12,23 @@ import "slick-carousel/slick/slick-theme.css";
import "./slider.css";
import type { ReactNode } from "react";
import type { CustomArrowProps } from "react-slick";
type SliderProps = {
items: ReactNode[];
};
type ArrowProps = CustomArrowProps & {
icon: ReactNode;
};
export const Slider = ({ items }: SliderProps) => {
const [range, setRange] = useState<number>(3);
const [activeRange, setActiveRange] = useState<number[]>([0, 1, 2]);
const theme = useTheme();
const isMiddle = useMediaQuery(
theme.breakpoints.down(1200) && theme.breakpoints.up(830)
);
const isMiddle = useMediaQuery(theme.breakpoints.down(1200));
const isTablet = useMediaQuery(theme.breakpoints.down(830));
const isMobileHeader = useMediaQuery(theme.breakpoints.down(900));
useEffect(() => {
if (isTablet) {
@ -64,10 +68,14 @@ export const Slider = ({ items }: SliderProps) => {
];
};
const Arrow = ({ currentSlide, slideCount, icon, ...props }: ArrowProps) => (
<Box {...props}>{icon}</Box>
);
return (
<Box className="slider-wrapper">
{(items.length < 4 && !isMiddle && !isTablet) ||
(items.length < 3 && isMiddle) ||
(items.length < 3 && isMiddle && !isTablet) ||
(items.length < 1 && isTablet) ? (
<Box
sx={{
@ -87,14 +95,15 @@ export const Slider = ({ items }: SliderProps) => {
dots
infinite
variableWidth
lazyLoad={isMobileHeader ? "progressive" : undefined}
slidesToShow={range}
prevArrow={<img src={arrowLeftIcon} alt="prev" />}
nextArrow={<img src={arrowRightIcon} alt="next" />}
prevArrow={<Arrow icon={<img src={arrowLeftIcon} alt="prev" />} />}
nextArrow={<Arrow icon={<img src={arrowRightIcon} alt="next" />} />}
beforeChange={(_, active) =>
setActiveRange(calculateRange(active, items.length))
}
customPaging={(slideNumber) => (
<li
<Box
className={classNames("dot", {
active: activeRange.includes(slideNumber),
})}

@ -84,14 +84,14 @@ export default function SigninDialog() {
sx: {
width: "600px",
maxWidth: "600px",
}
},
}}
slotProps={{
backdrop: {
style: {
backgroundColor: "rgb(0 0 0 / 0.7)",
}
}
},
},
}}
>
<Box

@ -16,7 +16,6 @@ import { makeRequest } from "@frontend/kitui";
import { cardShadow } from "@root/utils/themes/shadow";
import PasswordInput from "@root/components/passwordInput";
interface Values {
login: string;
password: string;
@ -31,13 +30,18 @@ const initialValues: Values = {
const validationSchema = object({
login: string().required("Поле обязательно"),
password: string().min(8, "Минимум 8 символов").matches(/^[.,:;-_+\d\w]+$/, "Некорректные символы").required("Поле обязательно"),
repeatPassword: string().oneOf([ref("password"), undefined], "Пароли не совпадают"),
password: string()
.min(8, "Минимум 8 символов")
.matches(/^[.,:;-_+\d\w]+$/, "Некорректные символы")
.required("Поле обязательно"),
repeatPassword: string()
.oneOf([ref("password"), undefined], "Пароли не совпадают")
.required("Повторите пароль"),
});
export default function SignupDialog() {
const [isDialogOpen, setIsDialogOpen] = useState<boolean>(true);
const user = useUserStore(state => state.user);
const user = useUserStore((state) => state.user);
const theme = useTheme();
const upMd = useMediaQuery(theme.breakpoints.up("md"));
const navigate = useNavigate();
@ -55,20 +59,26 @@ export default function SignupDialog() {
},
useToken: false,
withCredentials: true,
}).then(result => {
})
.then((result) => {
setUserId(result._id);
}).catch((error: any) => {
})
.catch((error: any) => {
const errorMessage = getMessageFromFetchError(error);
if (errorMessage) enqueueSnackbar(errorMessage);
}).finally(() => {
})
.finally(() => {
formikHelpers.setSubmitting(false);
});
},
});
useEffect(function redirectIfSignedIn() {
useEffect(
function redirectIfSignedIn() {
if (user) navigate("/tariffs", { replace: true });
}, [navigate, user]);
},
[navigate, user]
);
function handleClose() {
setIsDialogOpen(false);
@ -83,14 +93,14 @@ export default function SignupDialog() {
sx: {
width: "600px",
maxWidth: "600px",
}
},
}}
slotProps={{
backdrop: {
style: {
backgroundColor: "rgb(0 0 0 / 0.7)",
}
}
},
},
}}
>
<Box
@ -153,7 +163,7 @@ export default function SignupDialog() {
onBlur: formik.handleBlur,
error: formik.touched.password && Boolean(formik.errors.password),
helperText: formik.touched.password && formik.errors.password,
autoComplete: "new-password"
autoComplete: "new-password",
}}
onChange={formik.handleChange}
color="#F2F3F7"
@ -168,7 +178,7 @@ export default function SignupDialog() {
onBlur: formik.handleBlur,
error: formik.touched.repeatPassword && Boolean(formik.errors.repeatPassword),
helperText: formik.touched.repeatPassword && formik.errors.repeatPassword,
autoComplete: "new-password"
autoComplete: "new-password",
}}
onChange={formik.handleChange}
color="#F2F3F7"

@ -1,8 +1 @@
export const cardShadow = `
0px 100px 309px rgba(210, 208, 225, 0.24),
0px 41.7776px 129.093px rgba(210, 208, 225, 0.172525),
0px 22.3363px 69.0192px rgba(210, 208, 225, 0.143066),
0px 12.5216px 38.6916px rgba(210, 208, 225, 0.12),
0px 6.6501px 20.5488px rgba(210, 208, 225, 0.0969343),
0px 2.76726px 8.55082px rgba(210, 208, 225, 0.0674749)
`;
export const cardShadow = "0px 15px 80px rgb(210 208 225 / 70%)";

@ -2,11 +2,8 @@
"extends": "./tsconfig.extend.json",
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"lib": ["es5", "dom", "dom.iterable", "esnext"],
"types": ["node"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
@ -21,7 +18,5 @@
"noEmit": true,
"jsx": "react-jsx"
},
"include": [
"src"
]
"include": ["src", "**/*.ts"]
}

710
yarn.lock

File diff suppressed because it is too large Load Diff