Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
77def75671 | |||
c61aa5a5a7 | |||
e5610b3346 | |||
ad3929dd9f | |||
0c13ccf313 | |||
c97085b394 | |||
63fd61537c |
@ -3,12 +3,9 @@ include:
|
||||
file: "/templates/docker/build-template.gitlab-ci.yml"
|
||||
- project: "devops/pena-continuous-integration"
|
||||
file: "/templates/docker/deploy-template.gitlab-ci.yml"
|
||||
- project: "devops/pena-continuous-integration"
|
||||
file: "/templates/docker/service-discovery.gitlab-ci.yml"
|
||||
stages:
|
||||
- build
|
||||
- deploy
|
||||
- service-discovery
|
||||
|
||||
build-app:
|
||||
tags:
|
||||
@ -17,7 +14,7 @@ build-app:
|
||||
variables:
|
||||
DOCKER_BUILD_PATH: "./Dockerfile"
|
||||
STAGING_BRANCH: "staging"
|
||||
PRODUCTION_BRANCH: "main"
|
||||
PRODUCTION_BRANCH: "eng"
|
||||
|
||||
deploy-to-staging:
|
||||
extends: .deploy_template
|
||||
@ -29,11 +26,12 @@ deploy-to-staging:
|
||||
|
||||
deploy-to-prod:
|
||||
extends: .deploy_template
|
||||
variables:
|
||||
DOCKER_BUILD_PATH: "./Dockerfile"
|
||||
STAGING_BRANCH: "staging"
|
||||
PRODUCTION_BRANCH: "eng"
|
||||
rules:
|
||||
- if: "$CI_COMMIT_BRANCH == $PRODUCTION_BRANCH"
|
||||
tags:
|
||||
- front
|
||||
- prod
|
||||
|
||||
service-discovery:
|
||||
extends: .sd_artefacts_template
|
||||
|
13
deployments/eng/docker-compose.yaml
Normal file
13
deployments/eng/docker-compose.yaml
Normal file
@ -0,0 +1,13 @@
|
||||
version: "3"
|
||||
services:
|
||||
respen:
|
||||
container_name: respen
|
||||
restart: unless-stopped
|
||||
image: $CI_REGISTRY_IMAGE/eng:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
|
||||
hostname: respen
|
||||
tty: true
|
||||
networks:
|
||||
- main_default
|
||||
networks:
|
||||
main_default:
|
||||
external: true
|
@ -1,9 +1,8 @@
|
||||
version: "3"
|
||||
services:
|
||||
respondent:
|
||||
container_name: respondent
|
||||
respondent_en:
|
||||
container_name: respondent_en
|
||||
restart: unless-stopped
|
||||
image: $CI_REGISTRY_IMAGE/main:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
|
||||
hostname: respondent
|
||||
image: $CI_REGISTRY_IMAGE/eng:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
|
||||
hostname: respondent_en
|
||||
tty: true
|
||||
|
||||
|
BIN
dist-package.zip
Normal file
BIN
dist-package.zip
Normal file
Binary file not shown.
@ -20,8 +20,8 @@ import { ApologyPage } from "./ViewPublicationPage/ApologyPage";
|
||||
import ViewPublicationPage from "./ViewPublicationPage/ViewPublicationPage";
|
||||
import { HelmetProvider } from "react-helmet-async";
|
||||
|
||||
import "moment/dist/locale/ru";
|
||||
moment.locale("ru");
|
||||
import "moment/dist/locale/en-ca";
|
||||
moment.locale("en");
|
||||
const localeText = ruRU.components.MuiLocalizationProvider.defaultProps.localeText;
|
||||
|
||||
type Props = {
|
||||
|
@ -4,15 +4,7 @@ import { FallbackProps } from "react-error-boundary";
|
||||
type Props = Partial<FallbackProps>;
|
||||
|
||||
export const ApologyPage = ({ error }: Props) => {
|
||||
let message = "Что-то пошло не так";
|
||||
|
||||
if (error.response?.data === "quiz is inactive") message = "Квиз не активирован";
|
||||
if (error.message === "No questions found") message = "Нет созданных вопросов";
|
||||
if (error.message === "Quiz is empty") message = "Квиз пуст";
|
||||
if (error.message === "Quiz already completed") message = "Вы уже прошли этот опрос";
|
||||
if (error.message === "No quiz id") message = "Отсутствует id квиза";
|
||||
if (error.message === "Quiz data is null") message = "Не были переданы параметры квиза";
|
||||
if (error.response?.data === "Invalid request data") message = "Такого квиза не существует";
|
||||
let message = error?.message ?? error.response?.data ?? "Something went wrong";
|
||||
|
||||
return (
|
||||
<Box
|
||||
|
@ -85,7 +85,7 @@ export const ContactForm = ({ currentQuestion, onShowResult }: Props) => {
|
||||
if (email.length > 0) body.email = email;
|
||||
if (phone.length > 0) body.phone = phone;
|
||||
if (adress.length > 0) body.address = adress;
|
||||
if (text.length > 0) body.customs = { [FC.text.text || "Фамилия"]: text };
|
||||
if (text.length > 0) body.customs = { [FC.text.text || "Surname"]: text };
|
||||
|
||||
if (Object.keys(body).length > 0) {
|
||||
try {
|
||||
@ -99,7 +99,7 @@ export const ContactForm = ({ currentQuestion, onShowResult }: Props) => {
|
||||
const sessions = JSON.parse(localStorage.getItem("sessions") || "{}");
|
||||
localStorage.setItem("sessions", JSON.stringify({ ...sessions, [quizId]: new Date().getTime() }));
|
||||
} catch (e) {
|
||||
enqueueSnackbar("ответ не был засчитан");
|
||||
enqueueSnackbar("The answer was not counted");
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -119,12 +119,12 @@ export const ContactForm = ({ currentQuestion, onShowResult }: Props) => {
|
||||
const FC = settings.cfg.formContact.fields;
|
||||
|
||||
if (!isDisableEmail && FC["email"].used !== EMAIL_REGEXP.test(email)) {
|
||||
return enqueueSnackbar("введена некорректная почта");
|
||||
return enqueueSnackbar("Incorrect email entered");
|
||||
}
|
||||
|
||||
if (fireOnce.current) {
|
||||
if (name.length === 0 && email.length === 0 && phone.length === 0 && text.length === 0 && adress.length === 0)
|
||||
return enqueueSnackbar("Пожалуйста, заполните поля");
|
||||
return enqueueSnackbar("Please fill in the fields");
|
||||
|
||||
//почта валидна, хоть одно поле заполнено
|
||||
setFire(true);
|
||||
@ -159,7 +159,7 @@ export const ContactForm = ({ currentQuestion, onShowResult }: Props) => {
|
||||
yandexMetrics.contactsFormField("address");
|
||||
}
|
||||
} catch (e) {
|
||||
enqueueSnackbar("повторите попытку позже");
|
||||
enqueueSnackbar("please try again later");
|
||||
}
|
||||
if (settings.cfg.resultInfo.showResultForm === "after") {
|
||||
onShowResult();
|
||||
@ -281,22 +281,22 @@ export const ContactForm = ({ currentQuestion, onShowResult }: Props) => {
|
||||
}}
|
||||
fontSize={"16px"}
|
||||
>
|
||||
С 
|
||||
I agree with the 
|
||||
<Link
|
||||
href={"https://shub.pena.digital/ppdd"}
|
||||
target="_blank"
|
||||
>
|
||||
Положением об обработке персональных данных{" "}
|
||||
Regulation on the processing of personal data{" "}
|
||||
</Link>
|
||||
 и 
|
||||
 and the 
|
||||
<Link
|
||||
href={"https://shub.pena.digital/docs/privacy"}
|
||||
target="_blank"
|
||||
>
|
||||
{" "}
|
||||
Политикой конфиденциальности{" "}
|
||||
Privacy Policy{" "}
|
||||
</Link>
|
||||
 ознакомлен
|
||||
 agree
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
@ -315,7 +315,7 @@ export const ContactForm = ({ currentQuestion, onShowResult }: Props) => {
|
||||
},
|
||||
}}
|
||||
>
|
||||
{settings.cfg.formContact?.button || "Получить результаты"}
|
||||
{settings.cfg.formContact?.button || "Get results"}
|
||||
</Button>
|
||||
</Box>
|
||||
{show_badge && (
|
||||
|
@ -45,7 +45,7 @@ export const ContactTextBlock: FC<ContactTextBlockProps> = ({ settings }) => {
|
||||
wordBreak: "break-word",
|
||||
}}
|
||||
>
|
||||
{settings.cfg.formContact.title || "Заполните форму, чтобы получить результаты теста"}
|
||||
{settings.cfg.formContact.title || "Fill out the form to receive your test results"}
|
||||
</Typography>
|
||||
{settings.cfg.formContact.desc && (
|
||||
<Typography
|
||||
|
@ -45,8 +45,8 @@ export const Inputs = ({
|
||||
<CustomInput
|
||||
onChange={({ target }) => setName(target.value)}
|
||||
id={name}
|
||||
title={FC["name"].innerText || "Введите имя"}
|
||||
desc={FC["name"].text || "Имя"}
|
||||
title={FC["name"].innerText || "Enter your name"}
|
||||
desc={FC["name"].text || "Name"}
|
||||
Icon={NameIcon}
|
||||
/>
|
||||
);
|
||||
@ -56,7 +56,7 @@ export const Inputs = ({
|
||||
setEmail(target.value.replaceAll(/\s/g, ""));
|
||||
}}
|
||||
id={email}
|
||||
title={FC["email"].innerText || "Введите Email"}
|
||||
title={FC["email"].innerText || "Enter your Email"}
|
||||
desc={FC["email"].text || "Email"}
|
||||
Icon={EmailIcon}
|
||||
type="email"
|
||||
@ -70,8 +70,8 @@ export const Inputs = ({
|
||||
}}
|
||||
value={phone}
|
||||
id={phone}
|
||||
title={FC["phone"].innerText || "Введите номер телефона"}
|
||||
desc={FC["phone"].text || "Номер телефона"}
|
||||
title={FC["phone"].innerText || "Enter your phone number"}
|
||||
desc={FC["phone"].text || "Phone number"}
|
||||
Icon={PhoneIcon}
|
||||
isPhone={true}
|
||||
/>
|
||||
@ -80,8 +80,8 @@ export const Inputs = ({
|
||||
<CustomInput
|
||||
onChange={({ target }) => setText(target.value)}
|
||||
id={text}
|
||||
title={FC["text"].text || "Введите фамилию"}
|
||||
desc={FC["text"].innerText || "Фамилия"}
|
||||
title={FC["text"].text || "Enter your surname"}
|
||||
desc={FC["text"].innerText || "Surname"}
|
||||
Icon={TextIcon}
|
||||
/>
|
||||
);
|
||||
@ -89,8 +89,8 @@ export const Inputs = ({
|
||||
<CustomInput
|
||||
onChange={({ target }) => setAdress(target.value)}
|
||||
id={adress}
|
||||
title={FC["address"].innerText || "Введите адрес"}
|
||||
desc={FC["address"].text || "Адрес"}
|
||||
title={FC["address"].innerText || "Enter your address"}
|
||||
desc={FC["address"].text || "Address"}
|
||||
Icon={AddressIcon}
|
||||
/>
|
||||
);
|
||||
|
@ -41,7 +41,7 @@ export const Footer = ({ stepNumber, nextButton, prevButton }: FooterProps) => {
|
||||
{stepNumber !== null && (
|
||||
<Box sx={{ flexGrow: 1 }}>
|
||||
<Typography sx={{ color: theme.palette.text.primary }}>
|
||||
Вопрос {stepNumber} из {questionsAmount}
|
||||
Question {stepNumber} of {questionsAmount}
|
||||
</Typography>
|
||||
<Stepper
|
||||
activeStep={stepNumber}
|
||||
|
@ -58,7 +58,7 @@ export const PointSystemResultList = () => {
|
||||
color: theme.palette.text.primary,
|
||||
}}
|
||||
>
|
||||
{currentQuestion.title || "Вопрос без названия"}
|
||||
{currentQuestion.title || "Question without a title"}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Typography
|
||||
@ -81,7 +81,7 @@ export const PointSystemResultList = () => {
|
||||
color: theme.palette.grey[500],
|
||||
}}
|
||||
>
|
||||
Ваш ответ:
|
||||
Your answer:
|
||||
</Typography>
|
||||
<Box
|
||||
sx={{
|
||||
@ -135,7 +135,7 @@ const Line = ({ checkTrue, text }: LineProps) => {
|
||||
color: theme.palette.grey[500],
|
||||
}}
|
||||
>
|
||||
{text || "не выбрано"}
|
||||
{text || "not selected"}
|
||||
</Typography>
|
||||
</Box>
|
||||
);
|
||||
|
@ -35,7 +35,7 @@ export default function QuestionSelect({ selectedQuestion, setQuestion }: Props)
|
||||
id="category-select"
|
||||
variant="outlined"
|
||||
value={selectedQuestion.id}
|
||||
placeholder="Заголовок вопроса"
|
||||
placeholder="Question title"
|
||||
onChange={({ target }) => {
|
||||
setQuestion(target.value);
|
||||
}}
|
||||
|
@ -55,7 +55,7 @@ export const ResultForm = ({ resultQuestion }: ResultFormProps) => {
|
||||
const sessions = JSON.parse(localStorage.getItem("sessions") || "{}");
|
||||
localStorage.setItem("sessions", JSON.stringify({ ...sessions, [quizId]: new Date().getTime() }));
|
||||
} catch (e) {
|
||||
enqueueSnackbar("Заявка не может быть отправлена");
|
||||
enqueueSnackbar("The request could not be sent");
|
||||
}
|
||||
}
|
||||
if (Boolean(settings.cfg.score)) {
|
||||
@ -70,7 +70,7 @@ export const ResultForm = ({ resultQuestion }: ResultFormProps) => {
|
||||
const sessions = JSON.parse(localStorage.getItem("sessions") || "{}");
|
||||
localStorage.setItem("sessions", JSON.stringify({ ...sessions, [quizId]: new Date().getTime() }));
|
||||
} catch (e) {
|
||||
enqueueSnackbar("Количество баллов не может быть отправлено");
|
||||
enqueueSnackbar("The number of points could not be sent");
|
||||
}
|
||||
}
|
||||
})();
|
||||
@ -154,7 +154,7 @@ export const ResultForm = ({ resultQuestion }: ResultFormProps) => {
|
||||
wordBreak: "break-word",
|
||||
}}
|
||||
>
|
||||
Ваш результат:
|
||||
Your result:
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box
|
||||
@ -248,7 +248,7 @@ export const ResultForm = ({ resultQuestion }: ResultFormProps) => {
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
Ваши баллы
|
||||
Your points
|
||||
</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
@ -269,7 +269,7 @@ export const ResultForm = ({ resultQuestion }: ResultFormProps) => {
|
||||
},
|
||||
}}
|
||||
>
|
||||
Посмотреть ответы
|
||||
View answers
|
||||
</Typography>
|
||||
}
|
||||
sx={{
|
||||
@ -339,7 +339,7 @@ export const ResultForm = ({ resultQuestion }: ResultFormProps) => {
|
||||
height: "50px",
|
||||
}}
|
||||
>
|
||||
{resultQuestion.content.hint.text || "Узнать подробнее"}
|
||||
{resultQuestion.content.hint.text || "More information"}
|
||||
</Button>
|
||||
)}
|
||||
{settings.cfg.resultInfo.showResultForm === "after" && resultQuestion.content.redirect && (
|
||||
@ -361,7 +361,7 @@ export const ResultForm = ({ resultQuestion }: ResultFormProps) => {
|
||||
width: "auto",
|
||||
}}
|
||||
>
|
||||
{resultQuestion.content.hint.text || "Перейти на сайт"}
|
||||
{resultQuestion.content.hint.text || "Go to website"}
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
|
@ -302,7 +302,7 @@ export const StartPageViewPublication = () => {
|
||||
}}
|
||||
onClick={onQuizStart}
|
||||
>
|
||||
{settings.cfg.startpage.button.trim() ? settings.cfg.startpage.button : "Пройти тест"}
|
||||
{settings.cfg.startpage.button.trim() ? settings.cfg.startpage.button : "Take the test"}
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
|
@ -74,7 +74,7 @@ export default function ViewPublicationPage() {
|
||||
textAlign={"center"}
|
||||
mt="50px"
|
||||
>
|
||||
Вопрос не выбран
|
||||
Question not selected
|
||||
</Typography>
|
||||
</ThemeProvider>
|
||||
);
|
||||
@ -113,7 +113,7 @@ export default function ViewPublicationPage() {
|
||||
if (preview) return;
|
||||
|
||||
sendQuestionAnswer(quizId, currentQuestion, currentAnswer, ownVariants)?.catch((e) => {
|
||||
enqueueSnackbar("Ошибка при отправке ответа");
|
||||
enqueueSnackbar("Error sending answer");
|
||||
console.error("Error sending answer", e);
|
||||
});
|
||||
}}
|
||||
|
@ -50,7 +50,7 @@ export default ({ currentQuestion }: DateProps) => {
|
||||
}}
|
||||
>
|
||||
<Box>
|
||||
<span style={{ marginLeft: "25px", color: theme.palette.text.primary }}>От</span>
|
||||
<span style={{ marginLeft: "25px", color: theme.palette.text.primary }}>From</span>
|
||||
<DateCalendar
|
||||
sx={{
|
||||
"& .MuiInputBase-root": {
|
||||
@ -73,7 +73,7 @@ export default ({ currentQuestion }: DateProps) => {
|
||||
/>
|
||||
</Box>
|
||||
<Box>
|
||||
<span style={{ marginLeft: "25px", color: theme.palette.text.primary }}>До</span>
|
||||
<span style={{ marginLeft: "25px", color: theme.palette.text.primary }}>To</span>
|
||||
<DateCalendar
|
||||
sx={{
|
||||
"& .MuiInputBase-root": {
|
||||
|
@ -181,7 +181,7 @@ export const EmojiVariant = ({
|
||||
pl: "15px",
|
||||
}}
|
||||
>
|
||||
Введите свой ответ
|
||||
Enter your answer
|
||||
</Typography>
|
||||
)}
|
||||
<FormControlLabel
|
||||
|
@ -68,7 +68,7 @@ export const UploadFile = ({ currentQuestion, setModalWarningType, isSending, se
|
||||
updateAnswer(currentQuestion.id, `${file.name}|${URL.createObjectURL(file)}`, 0);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
enqueueSnackbar("ответ не был засчитан");
|
||||
enqueueSnackbar("the answer was not counted");
|
||||
}
|
||||
|
||||
setIsSending(false);
|
||||
|
@ -39,7 +39,7 @@ export const UploadedFile = ({ currentQuestion, setIsSending }: UploadedFileProp
|
||||
|
||||
return (
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: "15px" }}>
|
||||
<Typography color={theme.palette.text.primary}>Вы загрузили:</Typography>
|
||||
<Typography color={theme.palette.text.primary}>You have uploaded:</Typography>
|
||||
<Box
|
||||
sx={{
|
||||
padding: "5px 5px 5px 16px",
|
||||
|
@ -105,14 +105,14 @@ const CurrentModal = ({ status }: { status: ModalWarningType }) => {
|
||||
case null:
|
||||
return null;
|
||||
case "errorType":
|
||||
return <Typography>Выбран некорректный тип файла</Typography>;
|
||||
return <Typography>Incorrect file type selected</Typography>;
|
||||
case "errorSize":
|
||||
return <Typography>Файл слишком большой. Максимальный размер 50 МБ</Typography>;
|
||||
return <Typography>File is too big. Maximum size is 50 MB</Typography>;
|
||||
|
||||
default:
|
||||
return (
|
||||
<>
|
||||
<Typography>Допустимые расширения файлов:</Typography>
|
||||
<Typography>Acceptable file extensions:</Typography>
|
||||
<Typography>{ACCEPT_SEND_FILE_TYPES_MAP[status].join(" ")}</Typography>
|
||||
</>
|
||||
);
|
||||
|
@ -204,7 +204,7 @@ export const ImageVariant = ({
|
||||
pl: "15px",
|
||||
}}
|
||||
>
|
||||
Введите свой ответ
|
||||
Enter your answer
|
||||
</Typography>
|
||||
)}
|
||||
<FormControlLabel
|
||||
|
@ -368,7 +368,7 @@ export const Number = ({ currentQuestion }: NumberProps) => {
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Typography color={theme.palette.text.primary}>до</Typography>
|
||||
<Typography color={theme.palette.text.primary}>to</Typography>
|
||||
<CustomTextField
|
||||
placeholder="0"
|
||||
value={reversed ? String(reversedMaxRange) : maxRange}
|
||||
|
@ -195,7 +195,7 @@ export const VariantItem = ({
|
||||
top: "-23px",
|
||||
}}
|
||||
>
|
||||
Введите свой ответ
|
||||
Enter your answer
|
||||
</Typography>
|
||||
<OwnInput
|
||||
questionId={questionId}
|
||||
|
@ -127,7 +127,7 @@ export const VarimgVariant = ({
|
||||
pl: "15px",
|
||||
}}
|
||||
>
|
||||
Введите свой ответ
|
||||
Enter your answer
|
||||
</Typography>
|
||||
|
||||
<FormControlLabel
|
||||
|
@ -156,9 +156,9 @@ export const Varimg = ({ currentQuestion }: VarimgProps) => {
|
||||
) : currentQuestion.content.replText !== " " && currentQuestion.content.replText.length > 0 ? (
|
||||
currentQuestion.content.replText
|
||||
) : variant?.extendedText || isMobile ? (
|
||||
"Выберите вариант ответа ниже"
|
||||
"Select an answer option below"
|
||||
) : (
|
||||
"Выберите вариант ответа слева"
|
||||
"Select an answer option on the left"
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
|
@ -23,7 +23,7 @@ export default function NextButton({ isNextButtonEnabled, moveToNextQuestion }:
|
||||
}}
|
||||
onClick={moveToNextQuestion}
|
||||
>
|
||||
Далее →
|
||||
Next →
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ export default function PrevButton({ isPreviousButtonEnabled, moveToPrevQuestion
|
||||
}}
|
||||
onClick={moveToPrevQuestion}
|
||||
>
|
||||
{isMobileMini ? "←" : "← Назад"}
|
||||
{isMobileMini ? "←" : "← Back"}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
@ -4,15 +4,15 @@ export const MAX_FILE_SIZE = 419430400;
|
||||
|
||||
export const UPLOAD_FILE_DESCRIPTIONS_MAP = {
|
||||
picture: {
|
||||
title: "Добавить изображение",
|
||||
description: "Принимает изображения",
|
||||
title: "Add image",
|
||||
description: "Accepts images",
|
||||
},
|
||||
video: {
|
||||
title: "Добавить видео",
|
||||
description: "Принимает .mp4 и .mov формат — максимум 50мб",
|
||||
title: "Add video",
|
||||
description: "Accepts .mp4 and .mov format - maximum 50mb",
|
||||
},
|
||||
audio: { title: "Добавить аудиофайл", description: "Принимает аудиофайлы" },
|
||||
document: { title: "Добавить документ", description: "Принимает документы" },
|
||||
audio: { title: "Add audio file", description: "Accepts audio files" },
|
||||
document: { title: "Add document", description: "Accepts documents" },
|
||||
} as const satisfies Record<UploadFileType, { title: string; description: string }>;
|
||||
|
||||
export const ACCEPT_SEND_FILE_TYPES_MAP = {
|
||||
|
@ -1,10 +1,10 @@
|
||||
import type { QuizQuestionBase, QuestionHint, QuestionBranchingRule } from "./shared";
|
||||
|
||||
export const UPLOAD_FILE_TYPES_MAP = {
|
||||
picture: "Изображения",
|
||||
video: "Видео",
|
||||
audio: "Аудио",
|
||||
document: "Документ",
|
||||
picture: "Image",
|
||||
video: "Video",
|
||||
audio: "Audio",
|
||||
document: "Document",
|
||||
} as const;
|
||||
|
||||
export type UploadFileType = keyof typeof UPLOAD_FILE_TYPES_MAP;
|
||||
|
@ -6,44 +6,33 @@ export type ServerError = {
|
||||
message: string;
|
||||
};
|
||||
|
||||
const translateMessage: Record<string, string> = {
|
||||
"user not found": "Пользователь не найден",
|
||||
"invalid password": "Неправильный пароль",
|
||||
"field <password> is empty": 'Поле "Пароль" не заполнено',
|
||||
"field <login> is empty": 'Поле "Логин" не заполнено',
|
||||
"field <email> is empty": 'Поле "E-mail" не заполнено',
|
||||
"field <phoneNumber> is empty": 'Поле "Номер телефона" не заполнено',
|
||||
"user with this email or login is exist": "Пользователь уже существует",
|
||||
"user with this login is exist": "Пользователь с таким логином уже существует",
|
||||
};
|
||||
|
||||
export const parseAxiosError = (nativeError: unknown): [string, number?] => {
|
||||
const error = nativeError as AxiosError;
|
||||
|
||||
if (error.response?.data && "statusCode" in (error.response.data as ServerError)) {
|
||||
const serverError = error.response.data as ServerError;
|
||||
const translatedMessage = translateMessage[serverError.message];
|
||||
const translatedMessage = serverError.message;
|
||||
if (translatedMessage !== undefined) serverError.message = translatedMessage;
|
||||
return [serverError.message, serverError.statusCode];
|
||||
}
|
||||
|
||||
switch (error.status) {
|
||||
case 404:
|
||||
return ["Не найдено.", error.status];
|
||||
return ["Not found.", error.status];
|
||||
|
||||
case 403:
|
||||
return ["Доступ ограничен.", error.status];
|
||||
return ["Access is restricted.", error.status];
|
||||
|
||||
case 401:
|
||||
return ["Ошибка авторизации.", error.status];
|
||||
return ["Authorization error.", error.status];
|
||||
|
||||
case 500:
|
||||
return ["Внутренняя ошибка сервера.", error.status];
|
||||
return ["Internal Server Error.", error.status];
|
||||
|
||||
case 503:
|
||||
return ["Сервис недоступен.", error.status];
|
||||
return ["Service unavailable.", error.status];
|
||||
|
||||
default:
|
||||
return ["Неизвестная ошибка сервера."];
|
||||
return ["Unknown server error."];
|
||||
}
|
||||
};
|
||||
|
@ -5,14 +5,14 @@ import { StrictMode, lazy } from "react";
|
||||
|
||||
const routes: RouteObject[] = [
|
||||
{
|
||||
path: "/",
|
||||
path: "/en/",
|
||||
children: [
|
||||
{
|
||||
index: true,
|
||||
element: <App />,
|
||||
},
|
||||
{
|
||||
path: ":quizId",
|
||||
path: "/en/:quizId",
|
||||
element: <App />,
|
||||
},
|
||||
],
|
||||
|
@ -16,8 +16,8 @@ export default function QuizBanner({
|
||||
quizId,
|
||||
position,
|
||||
onWidgetClose,
|
||||
appealText = "Пройти тест",
|
||||
quizHeaderText = "Заголовок квиза",
|
||||
appealText = "Take the test",
|
||||
quizHeaderText = "Quiz Title",
|
||||
buttonTextColor,
|
||||
buttonBackgroundColor,
|
||||
autoShowQuizTime = null,
|
||||
@ -178,10 +178,16 @@ export default function QuizBanner({
|
||||
alignItems: "start",
|
||||
}}
|
||||
>
|
||||
<Typography fontSize="24px" lineHeight="120%">
|
||||
<Typography
|
||||
fontSize="24px"
|
||||
lineHeight="120%"
|
||||
>
|
||||
{appealText}
|
||||
</Typography>
|
||||
<Typography fontSize="44px" lineHeight="120%">
|
||||
<Typography
|
||||
fontSize="44px"
|
||||
lineHeight="120%"
|
||||
>
|
||||
{quizHeaderText}
|
||||
</Typography>
|
||||
</Box>
|
||||
@ -202,7 +208,11 @@ export default function QuizBanner({
|
||||
},
|
||||
}}
|
||||
>
|
||||
<svg viewBox="0 0 7 7" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg
|
||||
viewBox="0 0 7 7"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M1.00391 0.757812L6.67266 6.42656M1.00391 6.42656L6.67266 0.757812"
|
||||
stroke="white"
|
||||
|
@ -17,7 +17,7 @@ export default function OpenQuizButton({
|
||||
buttonFlash = false,
|
||||
withShadow = false,
|
||||
rounded = false,
|
||||
buttonText = "Пройти квиз",
|
||||
buttonText = "Take the quiz",
|
||||
buttonTextColor,
|
||||
buttonBackgroundColor,
|
||||
fullScreen = false,
|
||||
|
@ -120,7 +120,7 @@ export default function QuizSideButton({
|
||||
},
|
||||
]}
|
||||
>
|
||||
{buttonText || "Пройти квиз"}
|
||||
{buttonText || "Take the quiz"}
|
||||
{showButtonFlash && <RunningStripe />}
|
||||
</Button>
|
||||
</Fade>
|
||||
|
@ -16,6 +16,9 @@ export const alias = {
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
build: {
|
||||
assetsDir: "en/assets/",
|
||||
},
|
||||
resolve: {
|
||||
alias,
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user