Compare commits
No commits in common. "main" and "statistics_bugs" have entirely different histories.
main
...
statistics
@ -6,32 +6,20 @@ on:
|
|||||||
types: [published]
|
types: [published]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# CreateImage:
|
CreateImage:
|
||||||
# runs-on: [skeris]
|
runs-on: [skeris]
|
||||||
# uses: https://gitea.pena/PenaDevops/actions.git/.gitea/workflows/build-image.yml@v1.1.6-p
|
uses: https://gitea.pena/PenaDevops/actions.git/.gitea/workflows/build-image.yml@v1.1.6-p
|
||||||
# with:
|
with:
|
||||||
# runner: skeris
|
runner: skeris
|
||||||
# secrets:
|
secrets:
|
||||||
# REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
|
REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
|
||||||
# REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
|
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
|
||||||
# DeployService:
|
DeployService:
|
||||||
# runs-on: [frontprod]
|
runs-on: [frontprod]
|
||||||
# needs: CreateImage
|
needs: CreateImage
|
||||||
# uses: https://gitea.pena/PenaDevops/actions.git/.gitea/workflows/deploy.yml@v1.1.4-p7
|
uses: https://gitea.pena/PenaDevops/actions.git/.gitea/workflows/deploy.yml@v1.1.4-p7
|
||||||
# with:
|
with:
|
||||||
# runner: hubprod
|
runner: hubprod
|
||||||
# actionid: ${{ gitea.run_id }}
|
actionid: ${{ gitea.run_id }}
|
||||||
#
|
|
||||||
DeployService:
|
|
||||||
if: contains(github.event.package.name, 'main')
|
|
||||||
runs-on: [frontprod]
|
|
||||||
container:
|
|
||||||
image: gitea.pena/penadevops/container-images/node-compose:main
|
|
||||||
env:
|
|
||||||
GITHUB_RUN_NUMBER: "${{ inputs.actionid }}"
|
|
||||||
volumes:
|
|
||||||
- /run/user/1000/podman/podman.sock:/run/user/1000/podman/podman.sock
|
|
||||||
steps:
|
|
||||||
- name: Check out repository code
|
|
||||||
uses: http://gitea.pena/PenaDevops/actions.git/checkout@v1
|
|
||||||
- run: compose -f deployments/main/docker-compose.yaml up -d
|
|
||||||
|
@ -2,7 +2,6 @@ services:
|
|||||||
squiz:
|
squiz:
|
||||||
container_name: squiz
|
container_name: squiz
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
image: gitea.pena/squiz/frontpanel/main:latest
|
image: gitea.pena/squiz/frontpanel/main:$GITHUB_RUN_NUMBER
|
||||||
hostname: squiz
|
hostname: squiz
|
||||||
tty: true
|
tty: true
|
||||||
pull_policy: always
|
|
||||||
|
2675
package-lock.json
generated
2675
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -89,10 +89,12 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@emoji-mart/data": "^1.2.1",
|
"@emoji-mart/data": "^1.2.1",
|
||||||
"@emoji-mart/react": "^1.1.1",
|
"@emoji-mart/react": "^1.1.1",
|
||||||
|
"@types/cypress": "^1.1.6",
|
||||||
"@types/cytoscape-popper": "^2.0.4",
|
"@types/cytoscape-popper": "^2.0.4",
|
||||||
"@types/react-beautiful-dnd": "^13.1.4",
|
"@types/react-beautiful-dnd": "^13.1.4",
|
||||||
"@types/react-cytoscapejs": "^1.2.4",
|
"@types/react-cytoscapejs": "^1.2.4",
|
||||||
"craco-alias": "^3.0.1",
|
"craco-alias": "^3.0.1",
|
||||||
|
"cypress": "^14.4.1",
|
||||||
"husky": "^8.0.3",
|
"husky": "^8.0.3",
|
||||||
"lint-staged": "^15.2.0",
|
"lint-staged": "^15.2.0",
|
||||||
"prettier": "^3.1.1"
|
"prettier": "^3.1.1"
|
||||||
|
42
src/App.tsx
42
src/App.tsx
@ -277,10 +277,31 @@ export default function App() {
|
|||||||
path="/gallery"
|
path="/gallery"
|
||||||
element={<LazyLoading children={<QuizGallery />} />}
|
element={<LazyLoading children={<QuizGallery />} />}
|
||||||
/>
|
/>
|
||||||
|
<Route
|
||||||
|
path="/list"
|
||||||
|
element={
|
||||||
|
<LazyLoading
|
||||||
|
children={<MyQuizzesFull />}
|
||||||
|
fallback={<ListPageDummy />}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path={"/view/:quizId"}
|
||||||
|
element={<LazyLoading children={<ViewPage />} />}
|
||||||
|
/>
|
||||||
<Route
|
<Route
|
||||||
path={"/tariffs"}
|
path={"/tariffs"}
|
||||||
element={<LazyLoading children={<Tariffs />} />}
|
element={<LazyLoading children={<Tariffs />} />}
|
||||||
/>
|
/>
|
||||||
|
<Route
|
||||||
|
path={"/analytics"}
|
||||||
|
element={<LazyLoading children={<Analytics />} />}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path={"/results/:quizId"}
|
||||||
|
element={<LazyLoading children={<QuizAnswersPage />} />}
|
||||||
|
/>
|
||||||
<Route
|
<Route
|
||||||
path={"/qaz"}
|
path={"/qaz"}
|
||||||
element={<LazyLoading children={<InfoPrivilege />} />}
|
element={<LazyLoading children={<InfoPrivilege />} />}
|
||||||
@ -312,27 +333,6 @@ export default function App() {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
<Route
|
|
||||||
path="/list"
|
|
||||||
element={
|
|
||||||
<LazyLoading
|
|
||||||
children={<MyQuizzesFull />}
|
|
||||||
fallback={<ListPageDummy />}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
path={"/view/:quizId"}
|
|
||||||
element={<LazyLoading children={<ViewPage />} />}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
path={"/analytics"}
|
|
||||||
element={<LazyLoading children={<Analytics />} />}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
path={"/results/:quizId"}
|
|
||||||
element={<LazyLoading children={<QuizAnswersPage />} />}
|
|
||||||
/>
|
|
||||||
</Route>
|
</Route>
|
||||||
</Routes>
|
</Routes>
|
||||||
|
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
import { Box, SxProps } from "@mui/material";
|
|
||||||
import PostbackDefault from "./Postback";
|
|
||||||
import PostbackPC from "./PostbackPC";
|
|
||||||
|
|
||||||
export const PostbackLogo = (sx: SxProps) => (
|
|
||||||
<Box sx={{ display: "flex", alignItems: "center", gap: 1, ...sx }}>
|
|
||||||
<PostbackPC sx={{ width: "24px", height: "20px" }} />
|
|
||||||
<PostbackDefault sx={{ width: "40px", height: "8px" }} />
|
|
||||||
</Box>
|
|
||||||
);
|
|
@ -1,15 +0,0 @@
|
|||||||
import { Box, SxProps } from "@mui/material";
|
|
||||||
|
|
||||||
export const ZapierLogo = (sx: SxProps) => (
|
|
||||||
<Box
|
|
||||||
component="img"
|
|
||||||
src="/src/assets/icons/logo/zapier.png"
|
|
||||||
alt="Zapier"
|
|
||||||
sx={{
|
|
||||||
width: "40px",
|
|
||||||
height: "40px",
|
|
||||||
objectFit: "contain",
|
|
||||||
...sx,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
@ -18,7 +18,6 @@ import { ReactComponent as NextIcon } from "@icons/Analytics/next.svg";
|
|||||||
import { ReactComponent as LeftArrowIcon } from "@icons/Analytics/leftArrow.svg";
|
import { ReactComponent as LeftArrowIcon } from "@icons/Analytics/leftArrow.svg";
|
||||||
import { ReactComponent as RightArrowIcon } from "@icons/Analytics/rightArrow.svg";
|
import { ReactComponent as RightArrowIcon } from "@icons/Analytics/rightArrow.svg";
|
||||||
import { extractOrder } from "@utils/extractOrder";
|
import { extractOrder } from "@utils/extractOrder";
|
||||||
import { parseTitle } from "../utils/parseTitle";
|
|
||||||
|
|
||||||
type AnswerProps = {
|
type AnswerProps = {
|
||||||
title: string;
|
title: string;
|
||||||
@ -38,9 +37,7 @@ type PaginationProps = {
|
|||||||
|
|
||||||
const Answer = ({ title, percent, highlight }: AnswerProps) => {
|
const Answer = ({ title, percent, highlight }: AnswerProps) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const parsedTitle = parseTitle(title);
|
|
||||||
|
|
||||||
console.log("parsedTitle: " + parsedTitle);
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ padding: "15px 25px" }}>
|
<Box sx={{ padding: "15px 25px" }}>
|
||||||
<Box
|
<Box
|
||||||
@ -54,7 +51,7 @@ const Answer = ({ title, percent, highlight }: AnswerProps) => {
|
|||||||
>
|
>
|
||||||
<LinearProgress
|
<LinearProgress
|
||||||
variant="determinate"
|
variant="determinate"
|
||||||
title={parsedTitle}
|
title={title}
|
||||||
value={percent}
|
value={percent}
|
||||||
sx={{
|
sx={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
@ -64,7 +61,7 @@ const Answer = ({ title, percent, highlight }: AnswerProps) => {
|
|||||||
border: `1px solid ${highlight ? theme.palette.brightPurple.main : theme.palette.grey2.main}`,
|
border: `1px solid ${highlight ? theme.palette.brightPurple.main : theme.palette.grey2.main}`,
|
||||||
"& > span": { background: highlight ? "#D9C0F9" : "#9A9AAF1A" },
|
"& > span": { background: highlight ? "#D9C0F9" : "#9A9AAF1A" },
|
||||||
"&::before": {
|
"&::before": {
|
||||||
content: parsedTitle ? `"${parsedTitle}"` : `"Без имени"`,
|
content: title ? `"${title}"` : `"Без имени"`,
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
zIndex: 1,
|
zIndex: 1,
|
||||||
left: "20px",
|
left: "20px",
|
||||||
@ -280,12 +277,12 @@ export const Answers: FC<AnswersProps> = ({ data }) => {
|
|||||||
? ` ${currentAnswer?.[0]}`
|
? ` ${currentAnswer?.[0]}`
|
||||||
: "Без заголовка"}
|
: "Без заголовка"}
|
||||||
</Typography>
|
</Typography>
|
||||||
{/* <ButtonBase>
|
<ButtonBase>
|
||||||
<DoubleCheckIcon />
|
<DoubleCheckIcon />
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
<ButtonBase>
|
<ButtonBase>
|
||||||
<NextIcon />
|
<NextIcon />
|
||||||
</ButtonBase> */}
|
</ButtonBase>
|
||||||
</Box>
|
</Box>
|
||||||
{currentAnswerExtended.map(([title, percent], index) => (
|
{currentAnswerExtended.map(([title, percent], index) => (
|
||||||
<Answer
|
<Answer
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
/**
|
|
||||||
* Парсит title и извлекает Description из JSON строки
|
|
||||||
* @param title - строка, которая может быть JSON с Image и Description
|
|
||||||
* @returns значение Description или "нет названия" если парсинг не удался
|
|
||||||
*/
|
|
||||||
export const parseTitle = (title: string): string => {
|
|
||||||
if (!title || typeof title !== 'string') {
|
|
||||||
return "нет названия";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Убираем обратные кавычки если они есть
|
|
||||||
const cleanTitle = title.replace(/^`|`$/g, '');
|
|
||||||
|
|
||||||
// Проверяем, начинается ли строка с { и заканчивается на }
|
|
||||||
if (!cleanTitle.trim().startsWith('{') || !cleanTitle.trim().endsWith('}')) {
|
|
||||||
return title;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Пытаемся распарсить как JSON
|
|
||||||
const parsed = JSON.parse(cleanTitle);
|
|
||||||
console.log("parsed object:", parsed);
|
|
||||||
console.log("parsed.Image:", parsed.Image);
|
|
||||||
console.log("parsed.Description:", parsed.Description);
|
|
||||||
|
|
||||||
// Проверяем, что это объект с полями Image и Description (специфичный для вопросов типа images и varimg)
|
|
||||||
if (parsed &&
|
|
||||||
typeof parsed === 'object' &&
|
|
||||||
'Image' in parsed &&
|
|
||||||
'Description' in parsed) {
|
|
||||||
console.log("Returning Description:", parsed.Description);
|
|
||||||
return parsed.Description || "нет названия";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Если это не объект с Image и Description, возвращаем исходную строку
|
|
||||||
console.log("Not Image/Description object, returning original title");
|
|
||||||
return title;
|
|
||||||
} catch (error) {
|
|
||||||
// Если парсинг не удался, возвращаем исходную строку
|
|
||||||
console.log("JSON parse error, returning original title");
|
|
||||||
return title;
|
|
||||||
}
|
|
||||||
};
|
|
@ -132,7 +132,7 @@ export const PartnersBoard: FC<PartnersBoardProps> = ({
|
|||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* <Typography variant="h6" sx={sectionTitleStyles}>
|
<Typography variant="h6" sx={sectionTitleStyles}>
|
||||||
Автоматизация
|
Автоматизация
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box sx={containerStyles}>
|
<Box sx={containerStyles}>
|
||||||
@ -144,7 +144,7 @@ export const PartnersBoard: FC<PartnersBoardProps> = ({
|
|||||||
setIsModalOpen={setIsPostbackModalOpen}
|
setIsModalOpen={setIsPostbackModalOpen}
|
||||||
setCompanyName={setCompanyName}
|
setCompanyName={setCompanyName}
|
||||||
/>
|
/>
|
||||||
</Box> */}
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{companyName && (
|
{companyName && (
|
||||||
|
@ -26,12 +26,6 @@ export default function Component() {
|
|||||||
const userId = useUserStore((state) => state.userId);
|
const userId = useUserStore((state) => state.userId);
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
console.log("HeaderLanding debug:", {
|
|
||||||
userId,
|
|
||||||
location: location.pathname,
|
|
||||||
backgroundLocation: location.state?.backgroundLocation
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionStyled
|
<SectionStyled
|
||||||
tag={"header"}
|
tag={"header"}
|
||||||
@ -83,7 +77,6 @@ export default function Component() {
|
|||||||
to={"/signin"}
|
to={"/signin"}
|
||||||
state={{ backgroundLocation: location }}
|
state={{ backgroundLocation: location }}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
onClick={() => console.log("Signin button clicked")}
|
|
||||||
sx={{
|
sx={{
|
||||||
color: "black",
|
color: "black",
|
||||||
border: "1px solid black",
|
border: "1px solid black",
|
||||||
|
@ -23,12 +23,10 @@ type SettingTextFieldProps = {
|
|||||||
questionId: string;
|
questionId: string;
|
||||||
isRequired: boolean;
|
isRequired: boolean;
|
||||||
isAutofill: boolean;
|
isAutofill: boolean;
|
||||||
multi: boolean;
|
|
||||||
detailedAnswer: boolean;
|
|
||||||
answerType: Answer;
|
answerType: Answer;
|
||||||
};
|
};
|
||||||
|
|
||||||
const SettingTextField = memo<SettingTextFieldProps>(function ({ questionId, isRequired, detailedAnswer, multi, isAutofill, answerType }) {
|
const SettingTextField = memo<SettingTextFieldProps>(function ({ questionId, isRequired, isAutofill, answerType }) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
const isTablet = useMediaQuery(theme.breakpoints.down(900));
|
const isTablet = useMediaQuery(theme.breakpoints.down(900));
|
||||||
@ -147,21 +145,6 @@ const SettingTextField = memo<SettingTextFieldProps>(function ({ questionId, isR
|
|||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<CustomCheckbox
|
|
||||||
dataCy="checkbox-optional-question"
|
|
||||||
sx={{
|
|
||||||
display: isMobile ? "flex" : "block",
|
|
||||||
mr: isMobile ? "0px" : "16px",
|
|
||||||
alignItems: isMobile ? "flex-end" : "center",
|
|
||||||
}}
|
|
||||||
label={"Многострочный ответ"}
|
|
||||||
checked={multi}
|
|
||||||
handleChange={(e) => {
|
|
||||||
updateQuestion<QuizQuestionText>(questionId, (question) => {
|
|
||||||
question.content.multi = e.target.checked;
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
@ -17,8 +17,6 @@ export default function SwitchTextField({ switchState = "setting", question }: P
|
|||||||
isRequired={question.content.required}
|
isRequired={question.content.required}
|
||||||
isAutofill={question.content.autofill}
|
isAutofill={question.content.autofill}
|
||||||
answerType={question.content.answerType}
|
answerType={question.content.answerType}
|
||||||
detailedAnswer={Boolean(question.content?.detailedAnswer)}
|
|
||||||
multi={Boolean(question.content?.multi)}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case "image":
|
case "image":
|
||||||
|
@ -388,7 +388,7 @@ export const CardAnswer: FC<CardAnswerProps> = ({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{!(typeOuestion === "file" || typeOuestion === "images" || typeOuestion === "varimg") && (
|
{!(typeOuestion === "file" || typeOuestion === "images" || typeOuestion === "varimg") && (
|
||||||
<Typography sx={{ fontSize: "18px", whiteSpace: "pre-line" }}>{answer.content}</Typography>
|
<Typography sx={{ fontSize: "18px" }}>{answer.content}</Typography>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -22,7 +22,6 @@ import { makeRequest } from "@frontend/kitui";
|
|||||||
import { setAuthToken } from "@frontend/kitui";
|
import { setAuthToken } from "@frontend/kitui";
|
||||||
import { parseAxiosError } from "@utils/parse-error";
|
import { parseAxiosError } from "@utils/parse-error";
|
||||||
import { recoverUser } from "@api/user";
|
import { recoverUser } from "@api/user";
|
||||||
import PasswordInput from "@/ui_kit/passwordInput";
|
|
||||||
interface Values {
|
interface Values {
|
||||||
password: string;
|
password: string;
|
||||||
}
|
}
|
||||||
@ -55,8 +54,6 @@ export default function RecoverPassword() {
|
|||||||
initialValues,
|
initialValues,
|
||||||
validationSchema,
|
validationSchema,
|
||||||
onSubmit: async (values, formikHelpers) => {
|
onSubmit: async (values, formikHelpers) => {
|
||||||
console.log("tokenUser", tokenUser);
|
|
||||||
|
|
||||||
if (tokenUser) {
|
if (tokenUser) {
|
||||||
setAuthToken(tokenUser || "");
|
setAuthToken(tokenUser || "");
|
||||||
const [_, recoverError] = await recoverUser(values.password);
|
const [_, recoverError] = await recoverUser(values.password);
|
||||||
@ -77,12 +74,9 @@ export default function RecoverPassword() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log("RecoverPassword useEffect - window.location.search:", window.location.search);
|
|
||||||
console.log("RecoverPassword useEffect - window.location.href:", window.location.href);
|
|
||||||
const params = new URLSearchParams(window.location.search);
|
const params = new URLSearchParams(window.location.search);
|
||||||
const authToken = params.get("auth");
|
const authToken = params.get("auth");
|
||||||
console.log("RecoverPassword useEffect - authToken:", authToken);
|
setTokenUser(authToken);
|
||||||
setTokenUser(authToken || "");
|
|
||||||
|
|
||||||
history.pushState(null, document.title, "/changepwd");
|
history.pushState(null, document.title, "/changepwd");
|
||||||
return () => {
|
return () => {
|
||||||
@ -161,15 +155,13 @@ export default function RecoverPassword() {
|
|||||||
>
|
>
|
||||||
Введите новый пароль
|
Введите новый пароль
|
||||||
</Typography>
|
</Typography>
|
||||||
<PasswordInput
|
<InputTextfield
|
||||||
TextfieldProps={{
|
TextfieldProps={{
|
||||||
value: formik.values.password,
|
value: formik.values.password,
|
||||||
placeholder: "Не менее 8 символов",
|
placeholder: "введите пароль",
|
||||||
onBlur: formik.handleBlur,
|
onBlur: formik.handleBlur,
|
||||||
error: formik.touched.password && Boolean(formik.errors.password),
|
error: formik.touched.password && Boolean(formik.errors.password),
|
||||||
helperText: formik.touched.password && formik.errors.password,
|
helperText: formik.touched.password && formik.errors.password,
|
||||||
type: "password",
|
|
||||||
"data-cy": "password",
|
|
||||||
}}
|
}}
|
||||||
onChange={formik.handleChange}
|
onChange={formik.handleChange}
|
||||||
color="#F2F3F7"
|
color="#F2F3F7"
|
||||||
|
@ -875,24 +875,6 @@ export default function StartPageSettings() {
|
|||||||
Включить защиту от копирования
|
Включить защиту от копирования
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<Box sx={{ display: "flex", gap: "20px", alignItems: "center", mt: "20px" }}>
|
|
||||||
<CustomizedSwitch
|
|
||||||
checked={quiz.config?.backBlocked}
|
|
||||||
onChange={(e) => {
|
|
||||||
updateQuiz(quiz.id, (quiz) => {
|
|
||||||
quiz.config.backBlocked = e.target.checked;
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Typography
|
|
||||||
sx={{
|
|
||||||
fontWeight: 500,
|
|
||||||
color: theme.palette.grey3.main,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Запретить шаг назад
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
{!isSmallMonitor &&<SwitchAI />}
|
{!isSmallMonitor &&<SwitchAI />}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
@ -66,18 +66,7 @@ export const setUser = (user: User) =>
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const clearUserData = () => {
|
export const clearUserData = () => useUserStore.setState({ ...initialState });
|
||||||
console.log("clearUserData: Clearing user data");
|
|
||||||
console.log("clearUserData: Before clearing -", useUserStore.getState());
|
|
||||||
|
|
||||||
useUserStore.setState({ ...initialState });
|
|
||||||
|
|
||||||
console.log("clearUserData: After clearing -", useUserStore.getState());
|
|
||||||
|
|
||||||
// Также очищаем localStorage напрямую
|
|
||||||
localStorage.removeItem("user");
|
|
||||||
console.log("clearUserData: localStorage cleared");
|
|
||||||
};
|
|
||||||
|
|
||||||
export const setUserAccount = (userAccount: OriginalUserAccount) =>
|
export const setUserAccount = (userAccount: OriginalUserAccount) =>
|
||||||
useUserStore.setState({ userAccount });
|
useUserStore.setState({ userAccount });
|
||||||
|
@ -1,31 +1,8 @@
|
|||||||
import { useUserStore } from "@root/user";
|
import { useUserStore } from "@root/user";
|
||||||
import { Navigate, Outlet } from "react-router-dom";
|
import { Navigate, Outlet } from "react-router-dom";
|
||||||
import { useEffect } from "react";
|
|
||||||
|
|
||||||
export default function PrivateRoute() {
|
export default function PrivateRoute() {
|
||||||
const user = useUserStore((state) => state.user);
|
const user = useUserStore((state) => state.user);
|
||||||
const userId = useUserStore((state) => state.userId);
|
|
||||||
|
|
||||||
console.log("PrivateRoute debug:", {
|
return user ? <Outlet /> : <Navigate to="/" replace />;
|
||||||
user: user ? "exists" : "null",
|
|
||||||
userId: user?._id,
|
|
||||||
userIdFromStore: userId,
|
|
||||||
currentPath: window.location.pathname,
|
|
||||||
userObject: user
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!user) {
|
|
||||||
console.log("PrivateRoute: User is null, redirecting to / via useEffect");
|
|
||||||
window.location.href = "/";
|
|
||||||
}
|
|
||||||
}, [user]);
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
console.log("PrivateRoute: User is null, showing fallback");
|
|
||||||
return <></>;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("PrivateRoute: User exists, rendering Outlet");
|
|
||||||
return <Outlet />;
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import { cartApi } from "@api/cart";
|
|||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
import { enqueueSnackbar } from "notistack";
|
import { enqueueSnackbar } from "notistack";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useNavigate, useSearchParams, useLocation } from "react-router-dom";
|
import { useNavigate, useSearchParams } from "react-router-dom";
|
||||||
import { calcTimeOfReadyPayCart, cancelPayCartProcess, startPayCartProcess, useNotEnoughMoneyAmount } from "@/stores/notEnoughMoneyAmount";
|
import { calcTimeOfReadyPayCart, cancelPayCartProcess, startPayCartProcess, useNotEnoughMoneyAmount } from "@/stores/notEnoughMoneyAmount";
|
||||||
import { startCC } from "@/stores/cc";
|
import { startCC } from "@/stores/cc";
|
||||||
import { setEditQuizId, setCurrentStep } from "@root/quizes/actions";
|
import { setEditQuizId, setCurrentStep } from "@root/quizes/actions";
|
||||||
@ -17,7 +17,6 @@ import { setEditQuizId, setCurrentStep } from "@root/quizes/actions";
|
|||||||
export const useAfterPay = () => {
|
export const useAfterPay = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [searchParams, setSearchParams] = useSearchParams();
|
const [searchParams, setSearchParams] = useSearchParams();
|
||||||
const location = useLocation();
|
|
||||||
|
|
||||||
const userId = useUserStore(store => store.userId)
|
const userId = useUserStore(store => store.userId)
|
||||||
const userAccount = useUserStore(state => state.userAccount);
|
const userAccount = useUserStore(state => state.userAccount);
|
||||||
@ -29,28 +28,8 @@ export const useAfterPay = () => {
|
|||||||
let URLadditionalinformation = searchParams.get("additionalinformation");//его токен
|
let URLadditionalinformation = searchParams.get("additionalinformation");//его токен
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Проверяем, открыта ли модалка восстановления пароля
|
|
||||||
const isRecoverPasswordModal = location.state?.backgroundLocation?.pathname === "/changepwd";
|
|
||||||
|
|
||||||
// Проверяем, есть ли токен восстановления пароля в URL
|
setSearchParams({}, { replace: true });
|
||||||
const hasAuthToken = searchParams.get("auth") || window.location.search.includes("auth=");
|
|
||||||
|
|
||||||
console.log("useAfterPay debug:", {
|
|
||||||
pathname: location.pathname,
|
|
||||||
backgroundLocation: location.state?.backgroundLocation,
|
|
||||||
isRecoverPasswordModal,
|
|
||||||
searchParams: window.location.search,
|
|
||||||
authToken: searchParams.get("auth"),
|
|
||||||
hasAuthToken
|
|
||||||
});
|
|
||||||
|
|
||||||
// НЕ очищаем параметры на странице восстановления пароля, когда открыты модалки или есть токен auth
|
|
||||||
if (location.pathname !== "/changepwd" && !location.state?.backgroundLocation && !isRecoverPasswordModal && !hasAuthToken) {
|
|
||||||
console.log("Очищаем параметры URL");
|
|
||||||
setSearchParams({}, { replace: true });
|
|
||||||
} else {
|
|
||||||
console.log("НЕ очищаем параметры URL");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userId && URLuserId && userId === URLuserId) {
|
if (userId && URLuserId && userId === URLuserId) {
|
||||||
|
|
||||||
@ -99,7 +78,7 @@ export const useAfterPay = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}, [location.pathname, location.state?.backgroundLocation]);
|
}, []);
|
||||||
|
|
||||||
//Обработка необходимости купить после пополнения
|
//Обработка необходимости купить после пополнения
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
Loading…
Reference in New Issue
Block a user