From 39b0e0429397483fd95b82e522b5096d092e55d9 Mon Sep 17 00:00:00 2001 From: skeris Date: Wed, 14 May 2025 00:07:06 +0300 Subject: [PATCH 01/43] fix deploy staging --- .gitea/workflows/deployStaging.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/deployStaging.yml b/.gitea/workflows/deployStaging.yml index 3495235b..88de5f30 100644 --- a/.gitea/workflows/deployStaging.yml +++ b/.gitea/workflows/deployStaging.yml @@ -8,10 +8,10 @@ on: jobs: CreateImage: - runs-on: [hubstaging] + runs-on: [skeris] uses: http://gitea.pena/PenaDevops/actions.git/.gitea/workflows/build-image.yml@v1.1.6-p with: - runner: hubstaging + runner: skeris secrets: REGISTRY_USER: ${{ secrets.REGISTRY_USER }} REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }} From 93af4a0707f85a37bf663ce78cd62fa9dda898d5 Mon Sep 17 00:00:00 2001 From: Nastya Date: Sat, 17 May 2025 02:07:35 +0300 Subject: [PATCH 02/43] staging template --- .../createQuize/QuizGallery/templates/Auto.ts | 21 +++++----- .../QuizGallery/templates/Education.ts | 21 +++++----- .../QuizGallery/templates/Health.ts | 41 ++++++++++--------- .../QuizGallery/templates/Production.ts | 21 +++++----- .../QuizGallery/templates/RealEstate.ts | 21 +++++----- .../QuizGallery/templates/Repair.ts | 21 +++++----- .../QuizGallery/templates/Research.ts | 21 +++++----- .../QuizGallery/templates/Services.ts | 23 ++++++----- .../QuizGallery/templates/Tourism.ts | 21 +++++----- src/utils/hooks/useDomainDefine.ts | 3 ++ 10 files changed, 113 insertions(+), 101 deletions(-) diff --git a/src/pages/createQuize/QuizGallery/templates/Auto.ts b/src/pages/createQuize/QuizGallery/templates/Auto.ts index aecfc213..86547616 100644 --- a/src/pages/createQuize/QuizGallery/templates/Auto.ts +++ b/src/pages/createQuize/QuizGallery/templates/Auto.ts @@ -11,58 +11,59 @@ import AutoIcon8 from "@/assets/quiz-templates/auto/auto-8.jpg"; import AutoIcon9 from "@/assets/quiz-templates/auto/auto-9.jpg"; import AutoIcon10 from "@/assets/quiz-templates/auto/auto-10.jpg"; +import { isTestServer } from "@/utils/hooks/useDomainDefine"; export const AUTO_TEMPLATES: Category = { categoryType: "Auto", category: "Авто", templates: [ { - quizId: "eb885519-d9c2-41a5-a69c-6105d2bd9bef", + quizId: isTestServer ? "b1b0ed51-e2de-4b48-a8ca-d55e42b290ca" : "eb885519-d9c2-41a5-a69c-6105d2bd9bef", title: "Узнайте, что у вас с машиной", picture: AutoIcon1, }, { - quizId: "68f080e2-ae70-4a1a-be09-05c3decea592", + quizId: isTestServer ? "037f6f16-58e9-4854-a3fd-ccbdaa2ef901" : "68f080e2-ae70-4a1a-be09-05c3decea592", title: "Узнай стоимость и сроки выкупа своего автомобиля", picture: AutoIcon2, }, { - quizId: "446a5e79-8f10-4fb0-aa0f-165e3fbd8d36", + quizId: isTestServer ? "f5eadfa3-9cfc-4429-9854-380f5240fbbe" : "446a5e79-8f10-4fb0-aa0f-165e3fbd8d36", title: "Автошкола «Руль в Руки»", picture: AutoIcon3, }, { - quizId: "f30c7d80-852e-405d-8308-a124636b5ffa", + quizId: isTestServer ? "1f4d6841-9ee6-43ba-9d3d-929bbf2a5252" : "f30c7d80-852e-405d-8308-a124636b5ffa", title: "Узнайте, в какой компании выгодней КАСКО и ОСАГО", picture: AutoIcon4, }, { - quizId: "e200c96f-9c7a-4859-9bd2-65e42a6450b3", + quizId: isTestServer ? "dc5d523f-3922-4407-883c-22fc07f440d6" : "e200c96f-9c7a-4859-9bd2-65e42a6450b3", title: "Пройди тест, чтобы рассчитать стоимость необходимых детейлинг услуг", picture: AutoIcon5, }, { - quizId: "824c4553-ecb5-43e8-9b62-efc4844b01a8", + quizId: isTestServer ? "1e3dd6a6-34fb-44fc-9583-fd85de35b553" : "824c4553-ecb5-43e8-9b62-efc4844b01a8", title: "Онлайн-калькулятор шиномонтажных услуг", picture: AutoIcon6, }, { - quizId: "42423a16-1159-4c5c-bb45-4e9940ab6098", + quizId: isTestServer ? "15a14d9a-7afc-44f8-b162-eddcc327911a" : "42423a16-1159-4c5c-bb45-4e9940ab6098", title: "Калькулятор расчёта стоимости тонировки автомобиля", picture: AutoIcon7, }, { - quizId: "a0dfe680-30ff-4cac-91a5-28eb79889b68", + quizId: isTestServer ? "5c65c221-ac6d-4544-9f93-222b5790310b" : "a0dfe680-30ff-4cac-91a5-28eb79889b68", title: "Рассчитайте стоимость проката премиум-автомобиля за 3 минуты", picture: AutoIcon8, }, { - quizId: "18145500-1fdd-4814-9607-8775fb1a5ea7", + quizId: isTestServer ? "bec775f0-2e0a-47b2-8f74-4ab03ee0b29e" : "18145500-1fdd-4814-9607-8775fb1a5ea7", title: "Безопасное автокресло для вашего ребенка", picture: AutoIcon9, }, { - quizId: "63aa090c-8943-4a50-a10a-be394e75188b", + quizId: isTestServer ? "81a7b7e5-3045-4a5a-a850-b05d53d4bc82" : "63aa090c-8943-4a50-a10a-be394e75188b", title: "Подберём для вас премиум-автомобиль для проката", picture: AutoIcon10, }, diff --git a/src/pages/createQuize/QuizGallery/templates/Education.ts b/src/pages/createQuize/QuizGallery/templates/Education.ts index f8d012cf..5eb88288 100644 --- a/src/pages/createQuize/QuizGallery/templates/Education.ts +++ b/src/pages/createQuize/QuizGallery/templates/Education.ts @@ -11,59 +11,60 @@ import EductionIcon8 from "@/assets/quiz-templates/education/education-8.jpg"; import EductionIcon9 from "@/assets/quiz-templates/education/education-9.jpg"; import EductionIcon10 from "@/assets/quiz-templates/education/education-10.jpg"; +import { isTestServer } from "@/utils/hooks/useDomainDefine"; export const EDUCATION_TEMPLATES: Category = { categoryType: "Education", category: "Образование", templates: [ { - quizId: "27c10a81-f629-4af4-bdd0-2eb6c9cf10a8", + quizId: isTestServer ? "845cb5eb-bca8-495d-826f-e7b52a271b41" : "27c10a81-f629-4af4-bdd0-2eb6c9cf10a8", title: "Получите приглашение на занятие по программированию для ребёнка", picture: EductionIcon1, }, { - quizId: "bf9aaa3b-5d2d-4f82-9d5e-74862d73d10e", + quizId: isTestServer ? "33042986-9ff3-408e-898b-13b53319cb08" : "bf9aaa3b-5d2d-4f82-9d5e-74862d73d10e", title: "Научим играть любимую песню на фортепиано за 7 занятий", picture: EductionIcon2, }, { - quizId: "e2ed3948-6da2-48f4-86c7-42118b5abf85", + quizId: isTestServer ? "e7751cf8-467e-40e8-bd4d-0935ccab934b" : "e2ed3948-6da2-48f4-86c7-42118b5abf85", title: "Подбери репетитора для своего ребёнка со скидкой в 20%", picture: EductionIcon3, }, { - quizId: "076d3d12-c8f0-442a-b918-7f6085daa3ec", + quizId: isTestServer ? "a9e40faa-4cd5-495e-8812-acc0dde2dee2" : "076d3d12-c8f0-442a-b918-7f6085daa3ec", title: "Обратная связь о вебинаре", picture: EductionIcon4, }, { - quizId: "9914fe9c-19b4-47b1-aef8-a3c8e44f4c4c", + quizId: isTestServer ? "ab3fb1bc-afc8-4cf1-b77a-3fcff361d5be" : "9914fe9c-19b4-47b1-aef8-a3c8e44f4c4c", title: "Хотите выучить английский?", picture: EductionIcon5, }, { - quizId: "ec9c252e-ea2c-489a-809d-27522b7c1972", + quizId: isTestServer ? "a2900f7b-cf24-4a9b-b5da-f7f99dbd8a1b" : "ec9c252e-ea2c-489a-809d-27522b7c1972", title: "Ответьте на 4 вопроса и узнайте, куда записать ребенка чтобы развивать его таланты", picture: EductionIcon6, }, { - quizId: "45acb5b0-1dca-45fe-aaa0-88895bd5b237", + quizId: isTestServer ? "" : "45acb5b0-1dca-45fe-aaa0-88895bd5b237", title: "Поделитесь мнением о конференции", picture: EductionIcon7, }, { - quizId: "a9f17936-30c8-41ff-84d4-668840e02b56", + quizId: isTestServer ? "" : "a9f17936-30c8-41ff-84d4-668840e02b56", title: "Научитесь красиво петь и управлять своим голосом", picture: EductionIcon8, }, { - quizId: "51c4d927-4d27-405d-ab7e-6c2707418017", + quizId: isTestServer ? "" : "51c4d927-4d27-405d-ab7e-6c2707418017", title: "Узнайте, подойдёт ли вам профессия «Разработчик Phyton»?", categoryDescription: "(С ветвлением)", picture: EductionIcon9, }, { - quizId: "6063ee99-3188-43aa-89bc-895d90b08628", + quizId: isTestServer ? "e6dc608c-055a-44bd-ba2e-6cb185b378fe" : "6063ee99-3188-43aa-89bc-895d90b08628", title: "Проверьте своё знание английского языка", categoryDescription: "(С ветвлением)", picture: EductionIcon10, diff --git a/src/pages/createQuize/QuizGallery/templates/Health.ts b/src/pages/createQuize/QuizGallery/templates/Health.ts index f3879971..a11503b8 100644 --- a/src/pages/createQuize/QuizGallery/templates/Health.ts +++ b/src/pages/createQuize/QuizGallery/templates/Health.ts @@ -21,125 +21,126 @@ import HealthIcon18 from "@/assets/quiz-templates/health/health-18.jpg"; import HealthIcon19 from "@/assets/quiz-templates/health/health-19.jpg"; import HealthIcon20 from "@/assets/quiz-templates/health/health-20.jpg"; +import { isTestServer } from "@/utils/hooks/useDomainDefine"; export const HEALTH_TEMPLATES: Category = { categoryType: "Health", category: "Здоровье и уход", templates: [ { - quizId: "294c9c27-a189-4aa1-b792-a4d4612c99bf", + quizId: isTestServer ? "1927cf61-d80c-431c-8a04-4abca7c84b1e" : "294c9c27-a189-4aa1-b792-a4d4612c99bf", title: "Узнайте, сколько будет стоить ваш маникюр", categoryDescription: "Косметология", picture: HealthIcon1, }, { - quizId: "89fc7b57-9a13-4889-9e70-9d08714085f5", + quizId: isTestServer ? "cdb28a49-4bd4-411f-be8c-bc4bcdd577ab" : "89fc7b57-9a13-4889-9e70-9d08714085f5", title: "Узнайте стоимость услуг косметолога в Казани", categoryDescription: "Косметология", picture: HealthIcon2, }, { - quizId: "425c75c7-9412-485e-930f-3ae65f517fab", + quizId: isTestServer ? "6e6e8039-6d5e-4bc2-983a-f0e39f4b91c8" : "425c75c7-9412-485e-930f-3ae65f517fab", title: "Узнайте, как правильно ухаживать за вашим типом кожи в домашних условиях", categoryDescription: "Косметология", picture: HealthIcon3, }, { - quizId: "99461154-6296-4c8c-930d-2b1809f221cd", + quizId: isTestServer ? "1dcec3e5-5bfc-481a-bf80-5a1ca8941e89" : "99461154-6296-4c8c-930d-2b1809f221cd", title: "Какая косметологическая процедура вам нужна?", categoryDescription: "Косметология", picture: HealthIcon4, }, { - quizId: "cbf6a8d4-538a-4edf-9477-062a15361b04", + quizId: isTestServer ? "3cf82c7a-44c9-49d0-bbeb-97a84f6ebe8f" : "cbf6a8d4-538a-4edf-9477-062a15361b04", title: "5 вопросов до улыбки вашей мечты", categoryDescription: "Стоматология", picture: HealthIcon5, }, { - quizId: "017d9d5c-57a8-4eca-95c1-11db847a0e18", + quizId: isTestServer ? "3520c146-3cd9-43c6-9ef2-42571ff06a3e" : "017d9d5c-57a8-4eca-95c1-11db847a0e18", title: "Пройдите небольшой опрос, и узнайте, какая процедура у стоматолога вам нужна", categoryDescription: "Стоматология", picture: HealthIcon6, }, { - quizId: "162cb4f1-ab0a-49c4-b773-16932700f871", + quizId: isTestServer ? "aaa50e95-cd8c-4458-b82e-0139174d85ee" : "162cb4f1-ab0a-49c4-b773-16932700f871", title: "Какой врач мне нужен?", picture: HealthIcon7, }, { - quizId: "c851276b-505d-492b-9acb-5cd85e6fe3a7", + quizId: isTestServer ? "d81b56a0-0961-41ca-8816-cc391bf75efb" : "c851276b-505d-492b-9acb-5cd85e6fe3a7", title: "Психологическая помощь", categoryDescription: "Психолог", picture: HealthIcon8, }, { - quizId: "2fa1d438-72ac-49b2-95b6-73a8c9d8347a", + quizId: isTestServer ? "f4a0e414-b739-4a2e-8001-3de6eb1304c3" : "2fa1d438-72ac-49b2-95b6-73a8c9d8347a", title: "Ищешь психолога?", categoryDescription: "Психолог", picture: HealthIcon9, }, { - quizId: "b0b30965-ec43-4718-8a1f-2ae35f932a61", + quizId: isTestServer ? "f10774b0-23f6-4525-a2fd-b3ffd9d59cce" : "b0b30965-ec43-4718-8a1f-2ae35f932a61", title: "Подбор медицинского центра для лечебного массажа", categoryDescription: "Массаж", picture: HealthIcon10, }, { - quizId: "722aff37-d247-4341-9908-412e41f9d7cd", + quizId: isTestServer ? "418d735e-8134-4742-963b-8fdf392aebd3" : "722aff37-d247-4341-9908-412e41f9d7cd", title: "Исследование рынка мобильных приложений для здоровья", picture: HealthIcon11, }, { - quizId: "f0d800bc-2df0-42a6-8457-5c7759021854", + quizId: isTestServer ? "63552fb8-1586-4f14-a7c7-b75736294a87" : "f0d800bc-2df0-42a6-8457-5c7759021854", title: "Выполним стрижки и окрашивания любой сложности", categoryDescription: "Косметология", picture: HealthIcon12, }, { - quizId: "f88e2eb6-66e6-41ba-9d3d-1d7fe69d30d8", + quizId: isTestServer ? "4f4c6b83-a73c-4dbe-8776-ab93a073503d" : "f88e2eb6-66e6-41ba-9d3d-1d7fe69d30d8", title: "Массажный салон «Промято» в Ярославле", categoryDescription: "Массаж", picture: HealthIcon13, }, { - quizId: "9b2d47e8-d45f-48b7-a7fd-1c9c35edab17", + quizId: isTestServer ? "d47812bc-b7ac-4325-9eb1-496f1e60ab2c" : "9b2d47e8-d45f-48b7-a7fd-1c9c35edab17", title: "Подбери себе направление в йоге", categoryDescription: "Йога", picture: HealthIcon14, }, { - quizId: "8f6a1b3f-27fc-4e1c-a117-f67867e5df65", + quizId: isTestServer ? "bcd65cdd-07e7-480f-b305-596b815d1bb9" : "8f6a1b3f-27fc-4e1c-a117-f67867e5df65", title: "Подберите за 2 минуты рацион готового питания", categoryDescription: "Питание", picture: HealthIcon15, }, { - quizId: "73ff039f-3e93-4412-80ab-749f54c9bafa", + quizId: isTestServer ? "07f118c8-84fb-473a-9c83-357246fecaf1" : "73ff039f-3e93-4412-80ab-749f54c9bafa", title: "Рассчитайте стоимость установки грудных имплантов", picture: HealthIcon16, }, { - quizId: "2b4be94e-3505-41ae-85bb-c6c4a4d1bcd4", + quizId: isTestServer ? "ecba00e5-3990-4501-8b7a-fbee50383625" : "2b4be94e-3505-41ae-85bb-c6c4a4d1bcd4", title: "Не знаете, как выбрать очки? Подберите оправу под свои параметры", categoryDescription: "Зрение", picture: HealthIcon17, }, { - quizId: "28b133a5-0e6a-46b9-bd6b-81a44b808341", + quizId: isTestServer ? "1315b676-2abb-49e6-a959-89e2963bbe53" : "28b133a5-0e6a-46b9-bd6b-81a44b808341", title: "Санаторий в Подмосковье для пожилых людей", categoryDescription: "Санаторий", picture: HealthIcon18, }, { - quizId: "88a8e952-1475-4052-b99a-bbb7eb31249c", + quizId: isTestServer ? "d439fa6a-e13b-4a38-9bea-9414ee82c9fd" : "88a8e952-1475-4052-b99a-bbb7eb31249c", title: "Свежие блюда своими руками. 15 минут и готово", categoryDescription: "Питание", picture: HealthIcon19, }, { - quizId: "6baf144a-7401-442a-a513-6bc5aa3f1a6a", + quizId: isTestServer ? "de88083b-f02d-4a53-8afa-2c646d6aa588" : "6baf144a-7401-442a-a513-6bc5aa3f1a6a", title: "Рассчитайте стоимость отдыха в лучшей бане Москвы", picture: HealthIcon20, }, diff --git a/src/pages/createQuize/QuizGallery/templates/Production.ts b/src/pages/createQuize/QuizGallery/templates/Production.ts index a9ec3f22..24cf7280 100644 --- a/src/pages/createQuize/QuizGallery/templates/Production.ts +++ b/src/pages/createQuize/QuizGallery/templates/Production.ts @@ -11,58 +11,59 @@ import ProductionIcon8 from "@/assets/quiz-templates/production/production-8.jpg import ProductionIcon9 from "@/assets/quiz-templates/production/production-9.jpg"; import ProductionIcon10 from "@/assets/quiz-templates/production/production-10.jpg"; +import { isTestServer } from "@/utils/hooks/useDomainDefine"; export const PRODUCTION_TEMPLATES: Category = { categoryType: "Production", category: "Производство", templates: [ { - quizId: "14859665-e8ea-4e4a-b381-af88179f8ba3", + quizId: isTestServer ? "2745eb4a-e592-4319-9e6c-4e3f7b9503d2" : "14859665-e8ea-4e4a-b381-af88179f8ba3", title: "Рассчитайте стоимость постельного белья", picture: ProductionIcon1, }, { - quizId: "39cb17b6-10df-4107-abb8-6726d4845cbf", + quizId: isTestServer ? "1f18bf94-24c7-4f08-8362-e7efd2923359" : "39cb17b6-10df-4107-abb8-6726d4845cbf", title: "Ответьте на 4 вопроса и подберите межкомнатную дверь", picture: ProductionIcon2, }, { - quizId: "21b125ed-0213-4a3c-bd30-1a75b3953f4a", + quizId: isTestServer ? "75a52c54-9ebf-4785-bd11-8c432125005a" : "21b125ed-0213-4a3c-bd30-1a75b3953f4a", title: "Узнай стоимость производства и монтажа металлических ворот", picture: ProductionIcon3, }, { - quizId: "ed1a01f4-9497-4a79-adac-8f4fbf7f26f5", + quizId: isTestServer ? "2bc49b0b-e356-43bb-ac4e-37d135c48b2d" : "ed1a01f4-9497-4a79-adac-8f4fbf7f26f5", title: "Заполните анкету, чтобы заказать изготовление ювелирного изделия", picture: ProductionIcon4, }, { - quizId: "c94834f8-dd3a-43a0-8d40-6ebae4f475ed", + quizId: isTestServer ? "38880384-214d-4ac5-95f7-8ceb2f6060b5" : "c94834f8-dd3a-43a0-8d40-6ebae4f475ed", title: "Идеальный пол для любого помещения", picture: ProductionIcon5, }, { - quizId: "35ccb5b5-f4d2-4bbc-b172-5984356e7cfb", + quizId: isTestServer ? "d8189d8a-eb1d-41d7-9aee-62db91bd0ee0" : "35ccb5b5-f4d2-4bbc-b172-5984356e7cfb", title: "Рассчитайте стоимость изготовления зеркала", picture: ProductionIcon6, }, { - quizId: "e89d3758-2cfb-4566-9eb2-733c1c11ea03", + quizId: isTestServer ? "a1c7240c-af97-4405-9724-f02155e140df" : "e89d3758-2cfb-4566-9eb2-733c1c11ea03", title: "Подбери лучшие кеды", picture: ProductionIcon7, }, { - quizId: "26f00205-8373-4d00-bd93-7ced6cd0f509", + quizId: isTestServer ? "2031fe03-4f3e-4144-8cbf-26715b54d973" : "26f00205-8373-4d00-bd93-7ced6cd0f509", title: "Идеальная кровать для вашего ребенка", picture: ProductionIcon8, }, { - quizId: "4cc7cacf-30a9-4571-9319-dd186b915624", + quizId: isTestServer ? "46824071-75e7-4988-b157-960471ad7234" : "4cc7cacf-30a9-4571-9319-dd186b915624", title: "Рассчитайте стоимость кухни ручной работы из Италии с доставкой в Россию", picture: ProductionIcon9, }, { - quizId: "0d839f24-53e8-4dbd-9d9b-c57ac8e53a9c", + quizId: isTestServer ? "df3aff58-afb1-4876-a97a-2d792373894e" : "0d839f24-53e8-4dbd-9d9b-c57ac8e53a9c", title: "Узнайте примерную стоимость индивидуального пошива одежды", picture: ProductionIcon10, }, diff --git a/src/pages/createQuize/QuizGallery/templates/RealEstate.ts b/src/pages/createQuize/QuizGallery/templates/RealEstate.ts index bbe1bbd8..ecf18975 100644 --- a/src/pages/createQuize/QuizGallery/templates/RealEstate.ts +++ b/src/pages/createQuize/QuizGallery/templates/RealEstate.ts @@ -11,62 +11,63 @@ import RealEstateIcon8 from "@/assets/quiz-templates/real-estate/real-estate-8.j import RealEstateIcon9 from "@/assets/quiz-templates/real-estate/real-estate-9.jpg"; import RealEstateIcon10 from "@/assets/quiz-templates/real-estate/real-estate-10.jpg"; +import { isTestServer } from "@/utils/hooks/useDomainDefine"; export const REAL_ESTATE_TEMPLATES: Category = { categoryType: "RealEstate", category: "Недвижимость", templates: [ { - quizId: "d3930e95-ae95-4e2f-b9f9-79b929c2e1e6", + quizId: isTestServer ? "af9ed905-3947-4396-a9d9-a3b233451349" : "d3930e95-ae95-4e2f-b9f9-79b929c2e1e6", title: "Рассчитайте стоимость каркасного дома своей мечты", categoryDescription: "Строительство и ремонт", picture: RealEstateIcon1, }, { - quizId: "4e488b9b-d273-4f1c-b729-991fcbc006cd", + quizId: isTestServer ? "67b2c10a-a1f8-4eee-82a6-3aa7cd938566" : "4e488b9b-d273-4f1c-b729-991fcbc006cd", title: "Краткосрочная аренда коммерческих помещений", categoryDescription: "Аренда", picture: RealEstateIcon2, }, { - quizId: "84605c72-ce1d-49fb-a40e-7ed2ab96ac7d", + quizId: isTestServer ? "eacc428a-b724-4c26-9573-a179f23aef81" : "84605c72-ce1d-49fb-a40e-7ed2ab96ac7d", title: "Подберем новостройку под ваши критерии", picture: RealEstateIcon3, }, { - quizId: "ab701ab8-b8ad-4f45-a1ef-f0ab5357a587", + quizId: isTestServer ? "b77623d9-b73e-4eab-9137-6cd3e3722bfa" : "ab701ab8-b8ad-4f45-a1ef-f0ab5357a587", title: "15 лучших предложений от застройщиков в Москве", picture: RealEstateIcon4, }, { - quizId: "a5998d6c-c055-4702-bfc7-e1185fffa6c6", + quizId: isTestServer ? "8ebca441-50f2-4ed8-a648-fd35a86976e9" : "a5998d6c-c055-4702-bfc7-e1185fffa6c6", title: "Подберем идеальное жильё в Риме", picture: RealEstateIcon5, }, { - quizId: "bfbf97f2-3eba-4386-a794-4fa8f5825ac1", + quizId: isTestServer ? "1df0c5b6-5d15-427f-8972-651b0a8e67d7" : "bfbf97f2-3eba-4386-a794-4fa8f5825ac1", title: "Подбери уютный коттедж для отдыха в Подмосковье за 1 минуту", picture: RealEstateIcon6, }, { - quizId: "1b6ce902-0568-43c2-90a1-55dec710cb4f", + quizId: isTestServer ? "2857158a-18e0-4de7-bf0f-f1915ad95db1" : "1b6ce902-0568-43c2-90a1-55dec710cb4f", title: "Среди сотен новостроек подберём для вас самые подходящие", picture: RealEstateIcon7, }, { - quizId: "0dfa128f-8c2b-4519-8cf4-05f9171979e1", + quizId: isTestServer ? "df32e587-660c-4248-8fd3-c6e9b1752ae0" : "0dfa128f-8c2b-4519-8cf4-05f9171979e1", title: "Рассчитайте стоимость бронирования клуба для мероприятий", categoryDescription: "Aренда", picture: RealEstateIcon8, }, { - quizId: "8c4c8e3d-19cb-4c55-8952-558b877245bd", + quizId: isTestServer ? "9151a489-0d31-4442-a868-db0779322697" : "8c4c8e3d-19cb-4c55-8952-558b877245bd", title: "Запишитесь на консультацию и получите каталог объектов в перспективных районах Дубая", categoryDescription: "Услуги риелтора", picture: RealEstateIcon9, }, { - quizId: "36ebbe5d-4d85-453d-b5d2-51cdf7f95327", + quizId: isTestServer ? "6bcee3c8-951f-4745-8858-2b2cd6f6d282" : "36ebbe5d-4d85-453d-b5d2-51cdf7f95327", title: "Строим дома за 90 дней вместе со всеми коммуникациями и электричеством", categoryDescription: "Строительство и ремонт", diff --git a/src/pages/createQuize/QuizGallery/templates/Repair.ts b/src/pages/createQuize/QuizGallery/templates/Repair.ts index 2a378acc..2ec4b539 100644 --- a/src/pages/createQuize/QuizGallery/templates/Repair.ts +++ b/src/pages/createQuize/QuizGallery/templates/Repair.ts @@ -11,59 +11,60 @@ import RepairIcon8 from "@/assets/quiz-templates/repair/repair-8.jpg"; import RepairIcon9 from "@/assets/quiz-templates/repair/repair-9.jpg"; import RepairIcon10 from "@/assets/quiz-templates/repair/repair-10.jpg"; +import { isTestServer } from "@/utils/hooks/useDomainDefine"; export const REPAIR_TEMPLATES: Category = { categoryType: "Repair", category: "Ремонт", templates: [ { - quizId: "556760d9-652b-4ff1-91d5-3dc629650882", + quizId: isTestServer ? "d15ca3f0-8d59-4ac3-b168-6ac3246a22bb" : "556760d9-652b-4ff1-91d5-3dc629650882", title: "Капитальный ремонт квартир с фиксированной ценой", picture: RepairIcon1, }, { - quizId: "8f034581-71fb-467e-82dd-a415d4b8d73c", + quizId: isTestServer ? "62295ce9-58ad-42c5-9827-e3b180c8c4f7" : "8f034581-71fb-467e-82dd-a415d4b8d73c", title: "Натяжные потолки с гарантией 25 лет", picture: RepairIcon2, }, { - quizId: "fcb8c47b-f409-400c-b3d5-66657755f885", + quizId: isTestServer ? "d46febb0-3e79-4b83-8d7f-d104991a9359" : "fcb8c47b-f409-400c-b3d5-66657755f885", title: "Рассчитайте стоимость пластиковых окон", picture: RepairIcon3, }, { - quizId: "7544a8d3-ff03-491d-9189-1433fe307ad0", + quizId: isTestServer ? "d473b5a6-4d70-49d3-bacb-35ce21cd88fe" : "7544a8d3-ff03-491d-9189-1433fe307ad0", title: "Рассчитайте стоимость установки тёплого пола", picture: RepairIcon4, }, { - quizId: "dcf8bd1d-4c3f-4d1a-9efa-3d25991068f9", + quizId: isTestServer ? "a1bba994-a733-4817-a9bb-c64a68d670c8" : "dcf8bd1d-4c3f-4d1a-9efa-3d25991068f9", title: "Рассчитайте стоимость лестницы под ключ по вашим параметрам всего за одну минуту", picture: RepairIcon5, }, { - quizId: "2a921839-e5c8-45aa-afca-703d0dad8fad", + quizId: isTestServer ? "ad2fd24a-c28d-469c-95ea-78626fc51719" : "2a921839-e5c8-45aa-afca-703d0dad8fad", title: "Ответьте на 5 вопросов и рассчитайте стоимость вентиляции с монтажом под объект", picture: RepairIcon6, }, { - quizId: "ed13de01-f803-456a-b237-3644c808a0a1", + quizId: isTestServer ? "831303b3-aa9d-4115-936e-c46b899dd9b0" : "ed13de01-f803-456a-b237-3644c808a0a1", title: "Узнайте стоимость освещения вашего объекта", picture: RepairIcon7, }, { - quizId: "8d05e910-df1f-4ad3-9679-c0c3f7b7e575", + quizId: isTestServer ? "48c57689-3999-4f52-90ef-b26232fc400d" : "8d05e910-df1f-4ad3-9679-c0c3f7b7e575", title: "Узнайте стоимость кухни на заказ", picture: RepairIcon8, }, { - quizId: "9cabba56-2861-40dc-8f33-800745c3c949", + quizId: isTestServer ? "b61ca69f-d0e1-4754-ab91-2ec56fa45ca3" : "9cabba56-2861-40dc-8f33-800745c3c949", title: "Узнай стоимость дизайна интерьера под ключ", picture: RepairIcon9, }, { - quizId: "1c0eb1ad-ed3e-43f9-bcba-f094d13fef5b", + quizId: isTestServer ? "bc6aad09-b0e0-419c-87d8-6dd9770cc12e" : "1c0eb1ad-ed3e-43f9-bcba-f094d13fef5b", title: "Требуется штукатурка? Узнайте примерную стоимость работ и материалов.", picture: RepairIcon10, diff --git a/src/pages/createQuize/QuizGallery/templates/Research.ts b/src/pages/createQuize/QuizGallery/templates/Research.ts index a3554d52..1669aae5 100644 --- a/src/pages/createQuize/QuizGallery/templates/Research.ts +++ b/src/pages/createQuize/QuizGallery/templates/Research.ts @@ -11,57 +11,58 @@ import ResearchIcon8 from "@/assets/quiz-templates/research/research-8.jpg"; import ResearchIcon9 from "@/assets/quiz-templates/research/research-9.jpg"; import ResearchIcon10 from "@/assets/quiz-templates/research/research-10.jpg"; +import { isTestServer } from "@/utils/hooks/useDomainDefine"; export const RESEARCH_TEMPLATES: Category = { categoryType: "Research", category: "Исследовательские", templates: [ { - quizId: "1b356222-e762-4f3d-87e5-4c3d6c0a9467", + quizId: isTestServer ? "14f05b7d-abd1-4069-83ef-52e5fb748592" : "1b356222-e762-4f3d-87e5-4c3d6c0a9467", title: "Общественные настроения. Социальное самочувствие граждан", picture: ResearchIcon1, }, { - quizId: "7e901bea-6774-48b7-b31f-b62fd21ac88f", + quizId: isTestServer ? "b06f995a-7b35-493d-9614-a57cbbeae619" : "7e901bea-6774-48b7-b31f-b62fd21ac88f", title: "Социальные институты и проблемы общества", picture: ResearchIcon2, }, { - quizId: "2570ccef-563c-4d8e-a052-d6ad142fb789", + quizId: isTestServer ? "47a72329-e3fe-4164-94d2-87ec8471de39" : "2570ccef-563c-4d8e-a052-d6ad142fb789", title: "Уровень жизни населения", picture: ResearchIcon3, }, { - quizId: "b9394ed2-25e0-4e55-9d2a-9577856e903d", + quizId: isTestServer ? "54b0eccc-2ba2-4f48-8947-98449478a56f" : "b9394ed2-25e0-4e55-9d2a-9577856e903d", title: "Проблемы семьи и семейные отношения", picture: ResearchIcon4, }, { - quizId: "922088b6-9e02-4a0f-b6af-a7150781d4eb", + quizId: isTestServer ? "e7c67cc4-6e80-4c78-81d0-62669274fd3e" : "922088b6-9e02-4a0f-b6af-a7150781d4eb", title: "Здоровье и здравоохранение", picture: ResearchIcon5, }, { - quizId: "528ef773-2da5-4988-b687-b393d687ed00", + quizId: isTestServer ? "8c155f0c-9025-4779-be2c-17119a49fd40" : "528ef773-2da5-4988-b687-b393d687ed00", title: "Религия и Церковь", picture: ResearchIcon6, }, { - quizId: "8887c07c-831f-40c6-9bf7-951ab09546da", + quizId: isTestServer ? "afa35959-9df4-4ff8-9b3c-9a6ede888931" : "8887c07c-831f-40c6-9bf7-951ab09546da", title: "Трудоустройство молодежи", picture: ResearchIcon7, }, { - quizId: "850fde64-0462-40f7-992e-44fd0177e3b7", + quizId: isTestServer ? "75a252ec-b9e6-4764-acef-5d490a170e0b" : "850fde64-0462-40f7-992e-44fd0177e3b7", title: "Культура и ценности", picture: ResearchIcon8, }, { - quizId: "2c6ba86a-6c86-47b2-b71c-3c4ebaf29fbb", + quizId: isTestServer ? "18ca6609-5390-45ea-81e0-b6d3d26277bf" : "2c6ba86a-6c86-47b2-b71c-3c4ebaf29fbb", title: "Наука и технологии", picture: ResearchIcon9, }, { - quizId: "7ccd26ff-ccf5-4d6c-a148-1612a970211e", + quizId: isTestServer ? "cf3e02e5-b5d7-43d2-9ea3-888112387695" : "7ccd26ff-ccf5-4d6c-a148-1612a970211e", title: "Бизнес и предпринимательство", picture: ResearchIcon10, }, diff --git a/src/pages/createQuize/QuizGallery/templates/Services.ts b/src/pages/createQuize/QuizGallery/templates/Services.ts index 542a3263..153d868a 100644 --- a/src/pages/createQuize/QuizGallery/templates/Services.ts +++ b/src/pages/createQuize/QuizGallery/templates/Services.ts @@ -11,67 +11,68 @@ import ServiceIcon10 from "@/assets/quiz-templates/services/service-10.jpg"; import ServiceIcon11 from "@/assets/quiz-templates/services/service-11.jpg"; import type { Category } from "../Template"; +import { isTestServer } from "@/utils/hooks/useDomainDefine"; export const SERVICE_TEMPLATES: Category = { categoryType: "Services", category: "Услуги", templates: [ { - quizId: "a3490800-1ad3-4944-bb9c-32189d36b75c", + quizId: isTestServer ? "a055f7c1-34eb-4969-bf6a-1c701e1217b1" : "a3490800-1ad3-4944-bb9c-32189d36b75c", title: "Ответьте на 3 вопроса и узнайте, паспорт какой европейской страны вам подойдёт", picture: ServiceIcon1, }, { - quizId: "785fed83-6608-4029-ae22-6a26ce621e5f", + quizId: isTestServer ? "9fd1eff3-e342-4ae8-8e2a-2929c83af9cd" : "785fed83-6608-4029-ae22-6a26ce621e5f", title: "Ответьте на 7 вопросов, чтобы получить коммерческое предложение от маркетолога", picture: ServiceIcon2, }, { - quizId: "dfa3733f-66ce-4335-b83a-2c6511cbd1ce", + quizId: isTestServer ? "baf9468d-31b8-422f-9baa-efe2b00ac2af" : "dfa3733f-66ce-4335-b83a-2c6511cbd1ce", title: "Ответьте на пару вопросов, чтобы найти свой индивидуальный стиль одежды", picture: ServiceIcon3, }, { - quizId: "8bf582a9-0a66-4f7b-bc0f-3c2f656c7449", + quizId: isTestServer ? "934e9f8f-ab9c-443b-8693-ce132baae9d1" : "8bf582a9-0a66-4f7b-bc0f-3c2f656c7449", title: "Обменяйте рубли на валюту с комиссией 0%", picture: ServiceIcon4, }, { - quizId: "206ba071-afe9-4ee0-a722-a24a4f592679", + quizId: isTestServer ? "16cdb992-4338-417b-a8f5-0684c062e2cb" : "206ba071-afe9-4ee0-a722-a24a4f592679", title: "Рассчитайте стоимость уборки вашей квартиры", picture: ServiceIcon5, }, { - quizId: "6938ff93-52eb-4296-86bf-fe5aa3fddabf", + quizId: isTestServer ? "c3c5bf13-8498-4c35-9b58-1b9d6114fc47" : "6938ff93-52eb-4296-86bf-fe5aa3fddabf", title: "Забронируйте номер в зоогостинице для своего любимого питомца", picture: ServiceIcon6, }, { - quizId: "5262bc69-1ea0-446c-a16f-e929b6190e6d", + quizId: isTestServer ? "" : "5262bc69-1ea0-446c-a16f-e929b6190e6d", title: "Организуем перевозку под ключ", picture: ServiceIcon7, }, { - quizId: "9f8015f7-07fc-4acb-92dd-6e00505884cc", + quizId: isTestServer ? "37bc6554-1634-4b0c-8d95-abf589c8f56d" : "9f8015f7-07fc-4acb-92dd-6e00505884cc", title: "Рассчитайте стоимость ремонта пластиковых окон за 3 минуты", picture: ServiceIcon8, }, { - quizId: "259749bf-a54f-4a8e-ab5a-4cd0862d7504", + quizId: isTestServer ? "5ff47f56-2f50-42c8-af1e-936c8f63aca2" : "259749bf-a54f-4a8e-ab5a-4cd0862d7504", title: "Поможем подобрать эскиз для татуировки", picture: ServiceIcon9, }, { - quizId: "e107c0cd-4fa1-4a8f-938a-10a329b6528d", + quizId: isTestServer ? "4fc3dd99-b818-40ac-81d4-75150308608e" : "e107c0cd-4fa1-4a8f-938a-10a329b6528d", title: "Подбери себе лучшего юриста за 30 секунд", categoryDescription: "Юр услуги", picture: ServiceIcon10, }, { - quizId: "ce7903b1-3dfb-4a28-a2a4-0b41af447ae1", + quizId: isTestServer ? "ad4adfed-8e82-4d77-8675-6c024ab492ad" : "ce7903b1-3dfb-4a28-a2a4-0b41af447ae1", title: "Рассчитайте размер ипотечного кредитования, ответив на 4 вопроса", categoryDescription: "Юр услуги", picture: ServiceIcon11, diff --git a/src/pages/createQuize/QuizGallery/templates/Tourism.ts b/src/pages/createQuize/QuizGallery/templates/Tourism.ts index 1a16e7a5..e05fa388 100644 --- a/src/pages/createQuize/QuizGallery/templates/Tourism.ts +++ b/src/pages/createQuize/QuizGallery/templates/Tourism.ts @@ -10,58 +10,59 @@ import TourismIcon9 from "@/assets/quiz-templates/tourism/tourism-9.jpg"; import TourismIcon10 from "@/assets/quiz-templates/tourism/tourism-10.jpg"; import type { Category } from "../Template"; +import { isTestServer } from "@/utils/hooks/useDomainDefine"; export const TOURISM_TEMPLATES: Category = { categoryType: "Tourism", category: "Туризм", templates: [ { - quizId: "f7a2b3b8-2548-47d8-afb3-f2c69a3a0a81", + quizId: isTestServer ? "0d42bc16-c927-4d49-8764-deb4e4f14c4f" : "f7a2b3b8-2548-47d8-afb3-f2c69a3a0a81", title: "Подбор туристической страховки", picture: TourismIcon1, }, { - quizId: "e0927ded-5c4c-4d45-a5ba-c2e938362ffa", + quizId: isTestServer ? "897e3908-28e3-494e-a0be-0e3a0264b946" : "e0927ded-5c4c-4d45-a5ba-c2e938362ffa", title: "Оцените свои шансы на получение визы в США", picture: TourismIcon2, }, { - quizId: "23af97f4-0b8f-4d8b-8099-66ebef409ce1", + quizId: isTestServer ? "c4eec832-3e34-4486-b4db-e32812f924ea" : "23af97f4-0b8f-4d8b-8099-66ebef409ce1", title: "Персональный тур с лучшими местами в Германии", picture: TourismIcon3, }, { - quizId: "ca3bd705-7d41-4ff1-ae4c-0b2d4a8faa30", + quizId: isTestServer ? "67fbd981-e77d-4f43-8e37-9b2e94dc4afa" : "ca3bd705-7d41-4ff1-ae4c-0b2d4a8faa30", title: "Подберём лучший вариант тура под ваши критерии", picture: TourismIcon4, }, { - quizId: "5c2effd9-fe6a-40e6-9752-3f61dc20d6fa", + quizId: isTestServer ? "dd965dcf-aeca-4c39-8ee9-0dde372204b6" : "5c2effd9-fe6a-40e6-9752-3f61dc20d6fa", title: "Выберем самый подходящий для вас тур в Грузию", picture: TourismIcon5, }, { - quizId: "b559a764-6f55-4dc2-a9c4-aecd8b96003c", + quizId: isTestServer ? "e8d98b38-fbda-486e-b69a-b036f74703c8" : "b559a764-6f55-4dc2-a9c4-aecd8b96003c", title: "Бонжур, Сена! Подберём для вас тур по Франции", picture: TourismIcon6, }, { - quizId: "e33bf54b-9ad5-4cb9-b552-77148264d6af", + quizId: isTestServer ? "52018c8a-53e7-4d76-8fc3-4e3bd414ee3e" : "e33bf54b-9ad5-4cb9-b552-77148264d6af", title: "Персональный тур в Египет с лучшими местами страны", picture: TourismIcon7, }, { - quizId: "c5815b1d-4991-4df2-ae14-8713d7f313b9", + quizId: isTestServer ? "740b5ee8-0ab4-441f-8f75-e22b3a61ab36" : "c5815b1d-4991-4df2-ae14-8713d7f313b9", title: "Тур по местам России", picture: TourismIcon8, }, { - quizId: "a0a4dce8-43bb-4978-a802-96d384465df4", + quizId: isTestServer ? "5e0d7397-6e05-4f81-b24f-a625c2da12d3" : "a0a4dce8-43bb-4978-a802-96d384465df4", title: "Подберём для вас тур с самыми красивыми местами мира", picture: TourismIcon9, }, { - quizId: "0749abc5-a352-41b9-85c3-db7541326f23", + quizId: isTestServer ? "65fdf9a0-d30d-4728-abe3-b9a64c965269" : "0749abc5-a352-41b9-85c3-db7541326f23", title: "Выберем лучшие туристические места для вас", picture: TourismIcon10, }, diff --git a/src/utils/hooks/useDomainDefine.ts b/src/utils/hooks/useDomainDefine.ts index 73a893b7..ac809abc 100644 --- a/src/utils/hooks/useDomainDefine.ts +++ b/src/utils/hooks/useDomainDefine.ts @@ -11,3 +11,6 @@ export function useDomainDefine(): { isTestServer: boolean } { return { isTestServer }; } + +const host = window.location.hostname; +export const isTestServer = host.includes("s"); \ No newline at end of file From b9154061ec170cac8c376abfff9b1760873d8500 Mon Sep 17 00:00:00 2001 From: skeris Date: Sat, 17 May 2025 14:52:50 +0300 Subject: [PATCH 03/43] fix deployment --- deployments/staging/docker-compose.yaml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/deployments/staging/docker-compose.yaml b/deployments/staging/docker-compose.yaml index 6ba8ce9c..77b80c51 100644 --- a/deployments/staging/docker-compose.yaml +++ b/deployments/staging/docker-compose.yaml @@ -1,15 +1,7 @@ -version: "3" services: squiz: container_name: squiz restart: unless-stopped - image: $CI_REGISTRY_IMAGE/staging:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID - networks: - - marketplace_penahub_frontend - labels: - com.pena.domains: squiz.pena.digital + image: gitea.pena/squiz/frontpanel/staging:$GITHUB_RUN_NUMBER hostname: squiz tty: true -networks: - marketplace_penahub_frontend: - external: true From 22b61bed447a0470c391d3d14ca898b30b8d7393 Mon Sep 17 00:00:00 2001 From: Nastya Date: Sun, 18 May 2025 02:27:52 +0300 Subject: [PATCH 04/43] delete env dev --- .env.production.local | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env.production.local b/.env.production.local index 9183e8fb..fb98eb7c 100644 --- a/.env.production.local +++ b/.env.production.local @@ -1 +1 @@ -REACT_APP_DOMAIN="https://quiz.pena.digital" +REACT_APP_DOMAIN="" From 4eda62408004778a4b360b0808d13d6b108ba1c8 Mon Sep 17 00:00:00 2001 From: Nastya Date: Sun, 18 May 2025 15:54:58 +0300 Subject: [PATCH 05/43] update kit --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 466a2d68..d93a1b7f 100755 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "@craco/craco": "^7.0.0", "@emotion/react": "^11.10.5", "@emotion/styled": "^11.10.5", - "@frontend/kitui": "^1.0.88", + "@frontend/kitui": "^1.0.108", "@frontend/squzanswerer": "^1.0.57", "@mui/icons-material": "^5.10.14", "@mui/material": "^5.10.14", diff --git a/yarn.lock b/yarn.lock index 976cdd04..55a535c0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1235,7 +1235,7 @@ resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz#2cbcf822bf3764c9658c4d2e568bd0c0cb748016" integrity sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw== -"@emoji-mart/data@^1.1.2": +"@emoji-mart/data@^1.2.1": version "1.2.1" resolved "https://registry.yarnpkg.com/@emoji-mart/data/-/data-1.2.1.tgz#0ad70c662e3bc603e23e7d98413bd1e64c4fcb6c" integrity sha512-no2pQMWiBy6gpBEiqGeU77/bFejDqUTRY7KX+0+iur13op3bqUsXdnwoZs6Xb1zbv0gAj5VvS1PWoUUckSr5Dw== @@ -1411,10 +1411,10 @@ resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.9.tgz#50dea3616bc8191fb8e112283b49eaff03e78429" integrity sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg== -"@frontend/kitui@^1.0.88": - version "1.0.92" - resolved "http://gitea.pena/api/packages/skeris/npm/%40frontend%2Fkitui/-/1.0.92/kitui-1.0.92.tgz#9e75e1d0b3dbcc8744aea0402f40416d7a540c73" - integrity sha512-r/+rJbo63XpaivtMalZ0x5rxj3oIfLWQxJ3OqvohFVy+JF/e2FEgePVl2BvomcjYDeTM1eJru+nmvzONdMTfCA== +"@frontend/kitui@^1.0.108": + version "1.0.108" + resolved "http://gitea.pena/api/packages/skeris/npm/%40frontend%2Fkitui/-/1.0.108/kitui-1.0.108.tgz#1bb609dfe07668b6fd9a7b8618c229e0bb609f1e" + integrity sha512-4DiF7GHX0RbBMZpFioclc3B87N+HrGLv1B3DveUCdHzukfxvFXyEKnRZQ4wYljO2A3FLSD9+4Dr6cSuZYw95OQ== dependencies: immer "^10.0.2" reconnecting-eventsource "^1.6.2" From c6cb130d5b39f85fd9a1347821e73df0cda71cf4 Mon Sep 17 00:00:00 2001 From: Nastya Date: Tue, 20 May 2025 16:22:17 +0300 Subject: [PATCH 06/43] =?UTF-8?q?=D0=B4=D0=B0=D1=82=D1=8B=20=D0=BD=D0=B0?= =?UTF-8?q?=20general=20=D0=B0=D0=BD=D0=B0=D0=BB=D0=B8=D1=82=D0=B8=D0=BA?= =?UTF-8?q?=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Analytics/General.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pages/Analytics/General.tsx b/src/pages/Analytics/General.tsx index 306b1d4e..be9b7b88 100644 --- a/src/pages/Analytics/General.tsx +++ b/src/pages/Analytics/General.tsx @@ -83,11 +83,11 @@ const GeneralItem = ({ xAxis={[ { data: statiscticsResult ? days : Object.keys(general), - valueFormatter: (value) => - moment.unix(Number(value)).format("DD/MM/YYYY HH") + - statiscticsResult - ? "" - : "ч", + valueFormatter: (value) => { + const timestamp = Number(value); + if (isNaN(timestamp)) return 'Invalid Date'; + return moment.unix(timestamp).format(statiscticsResult ? "DD/MM/YYYY" : "DD/MM/YYYY HH") + (statiscticsResult ? "" : "ч"); + }, }, ]} series={[ From aa917fe6baf0f3d8d6d9fa5c236defd6c97a5896 Mon Sep 17 00:00:00 2001 From: Nastya Date: Thu, 22 May 2025 00:37:21 +0300 Subject: [PATCH 07/43] fix dragdrop --- .../Questions/AnswerDraggableList/index.tsx | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/pages/Questions/AnswerDraggableList/index.tsx b/src/pages/Questions/AnswerDraggableList/index.tsx index 6db802bb..b5f41dc2 100644 --- a/src/pages/Questions/AnswerDraggableList/index.tsx +++ b/src/pages/Questions/AnswerDraggableList/index.tsx @@ -2,7 +2,11 @@ import { Box } from "@mui/material"; import { reorderQuestionVariants } from "@root/questions/actions"; import { type ReactNode } from "react"; import type { DropResult } from "react-beautiful-dnd"; -import { DragDropContext, Droppable } from "react-beautiful-dnd"; +import { DragDropContext as DragDropContextOriginal } from "react-beautiful-dnd"; +import { StrictModeDroppable } from "./StrictModeDroppable"; + +// Исправляем типизацию для DragDropContext +const DragDropContext = DragDropContextOriginal as any; type AnswerDraggableListProps = { questionId: string; @@ -14,21 +18,36 @@ export const AnswerDraggableList = ({ variants, }: AnswerDraggableListProps) => { const onDragEnd = ({ destination, source }: DropResult) => { - if (destination) { + // Проверяем наличие необходимых данных + if (!destination || !source) return; + + // Проверяем, что индексы действительно изменились + if (destination.index === source.index) return; + + // Проверяем валидность индексов + if (source.index < 0 || destination.index < 0) return; + + try { reorderQuestionVariants(questionId, source.index, destination.index); + } catch (error) { + console.error('Error reordering variants:', error); + // Здесь можно добавить уведомление пользователю об ошибке } }; return ( - + {(provided) => ( - + {variants} {provided.placeholder} )} - + ); }; From e2e391325bb6a946f3b4802050ed3113bdf07db1 Mon Sep 17 00:00:00 2001 From: Nastya Date: Thu, 22 May 2025 23:10:15 +0300 Subject: [PATCH 08/43] nko --- src/pages/Tariffs/tariffsUtils/createTariffElements.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/Tariffs/tariffsUtils/createTariffElements.tsx b/src/pages/Tariffs/tariffsUtils/createTariffElements.tsx index 7aad4952..7999e51f 100644 --- a/src/pages/Tariffs/tariffsUtils/createTariffElements.tsx +++ b/src/pages/Tariffs/tariffsUtils/createTariffElements.tsx @@ -19,6 +19,8 @@ export const createTariffElements = ( ) => { console.log("start work createTariffElements") console.log("filteredTariffs ", filteredTariffs) + console.log("user ", user) + console.log("user.isUserNko, ", user.isUserNko) const tariffElements = filteredTariffs .filter((tariff) => tariff.privileges.length > 0) .map((tariff, index) => { @@ -27,7 +29,7 @@ export const createTariffElements = ( discounts, user.wallet.spent, [], - user.isUserNko, + user.status === "nko", user.userId, ); From 262337272f5f96641f4bc4797e51fe4dc99ff7f3 Mon Sep 17 00:00:00 2001 From: Nastya Date: Sun, 25 May 2025 16:21:19 +0300 Subject: [PATCH 09/43] first AI page --- src/App.tsx | 7 + src/assets/icons/AiPersonalizationIcon.svg | 5 + src/assets/icons/AiPersonalizationIcon.tsx | 12 ++ .../GenderAndAgeSelector.tsx | 172 ++++++++++++++++++ .../PersonalizationAI/PersonalizationAI.tsx | 167 +++++++++++++++++ src/ui_kit/InfoPopover.tsx | 53 ++++++ src/ui_kit/Sidebar/Sidebar.tsx | 15 ++ 7 files changed, 431 insertions(+) create mode 100644 src/assets/icons/AiPersonalizationIcon.svg create mode 100644 src/assets/icons/AiPersonalizationIcon.tsx create mode 100644 src/pages/PersonalizationAI/GenderAndAgeSelector.tsx create mode 100644 src/pages/PersonalizationAI/PersonalizationAI.tsx create mode 100644 src/ui_kit/InfoPopover.tsx diff --git a/src/App.tsx b/src/App.tsx index 68b6ad6d..d6195646 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -35,6 +35,7 @@ const { DesignPage } = lazily(() => import("./pages/DesignPage/DesignPage")); const { IntegrationsPage } = lazily(() => import("./pages/IntegrationsPage/IntegrationsPage")); const { QuizAnswersPage } = lazily(() => import("./pages/QuizAnswersPage/QuizAnswersPage")); const ChatImageNewWindow = lazy(() => import("@ui_kit/FloatingSupportChat/ChatImageNewWindow")); +const PersonalizationAI = lazy(() => import("./pages/PersonalizationAI/PersonalizationAI")); let params = new URLSearchParams(document.location.search); const isTest = Boolean(params.get("test")) @@ -60,6 +61,12 @@ const routeslink = [ sidebar: true, footer: true, }, + { + path: "/personalization-ai", + page: PersonalizationAI, + header: true, + sidebar: true, + }, ] as const; const LazyLoading = ({ children, fallback }: SuspenseProps) => ( diff --git a/src/assets/icons/AiPersonalizationIcon.svg b/src/assets/icons/AiPersonalizationIcon.svg new file mode 100644 index 00000000..74f20dc9 --- /dev/null +++ b/src/assets/icons/AiPersonalizationIcon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/AiPersonalizationIcon.tsx b/src/assets/icons/AiPersonalizationIcon.tsx new file mode 100644 index 00000000..fc815fa1 --- /dev/null +++ b/src/assets/icons/AiPersonalizationIcon.tsx @@ -0,0 +1,12 @@ +import * as React from "react"; +import { SvgIcon, SvgIconProps } from "@mui/material"; + +const AiPersonalizationIcon = (props: SvgIconProps) => ( + + + + + +); + +export default AiPersonalizationIcon; \ No newline at end of file diff --git a/src/pages/PersonalizationAI/GenderAndAgeSelector.tsx b/src/pages/PersonalizationAI/GenderAndAgeSelector.tsx new file mode 100644 index 00000000..f3aff559 --- /dev/null +++ b/src/pages/PersonalizationAI/GenderAndAgeSelector.tsx @@ -0,0 +1,172 @@ +import { Box, FormControl, FormLabel, RadioGroup, FormControlLabel, Radio, Select, MenuItem, useTheme } from "@mui/material"; +import { InfoPopover } from '@ui_kit/InfoPopover'; +import CheckboxIcon from "@icons/Checkbox"; + +interface GenderAndAgeSelectorProps { + gender: string; + setGender: (gender: string) => void; +} + +export default function GenderAndAgeSelector({ gender, setGender }: GenderAndAgeSelectorProps) { + const theme = useTheme(); + return ( + + + + + + + Пол + + + setGender(e.target.value)}> + + } checkedIcon={} />} label="М" /> + } checkedIcon={} />} label="Ж" /> + + + + + + + + Возраст + + + + + + ); +} \ No newline at end of file diff --git a/src/pages/PersonalizationAI/PersonalizationAI.tsx b/src/pages/PersonalizationAI/PersonalizationAI.tsx new file mode 100644 index 00000000..80331c4a --- /dev/null +++ b/src/pages/PersonalizationAI/PersonalizationAI.tsx @@ -0,0 +1,167 @@ +import { Box, Container, Typography, TextField, Button, List, ListItem, IconButton } from "@mui/material"; +import { InfoPopover } from '@ui_kit/InfoPopover'; +import CopyIcon from "@/assets/icons/CopyIcon"; +import GenderAndAgeSelector from "./GenderAndAgeSelector"; +import { useState } from "react"; +import CustomTextField from "@ui_kit/CustomTextField"; +import Collapse from '@mui/material/Collapse'; +import { ArrowDownIcon } from "../../assets/icons/questionsPage/ArrowDownIcon"; +import { useTheme } from "@mui/material"; + +const PURPLE = "#7E2AEA"; +const GREY_TEXT = "#A0A0A0"; +const GREY_BORDER = "#E0E0E0"; +const GREY_ICON = "#B0B0B0"; +const BLOCK_RADIUS = "16px"; +const BLOCK_PX = "32px"; +const BLOCK_PY = "24px"; + +export default function PersonalizationAI() { + const [gender, setGender] = useState(''); + const [linksOpen, setLinksOpen] = useState(true); + const theme = useTheme(); + + return ( + + + Персонализация вопросов с помощью AI + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. + + + {/* Первый белый блок */} + + + + + + + {/* Ссылка */} + + + Ссылка + + + + Вставьте ссылку со всеми utm-метками + + + + + + + + + {/* Второй белый блок */} + + + + Ваши сохраненные ссылки + + setLinksOpen((prev) => !prev)} + size="large" + > + + + + + + {[1, 2, 3, 4, 5].map((_, idx) => ( + + + + + + + + + + } + > + + linkexample.ru + + + ))} + + + + + ); +} diff --git a/src/ui_kit/InfoPopover.tsx b/src/ui_kit/InfoPopover.tsx new file mode 100644 index 00000000..8ce59e2e --- /dev/null +++ b/src/ui_kit/InfoPopover.tsx @@ -0,0 +1,53 @@ +import { useState, MouseEvent } from "react"; +import Info from "@icons/Info"; + +import { Paper, Popover, SxProps, Typography } from "@mui/material"; + +export const InfoPopover = ({ blink = false, sx }: {blink?: boolean, sx?: SxProps}) => { + const [anchorEl, setAnchorEl] = useState(null); + + const handleClick = (event: MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + + const handleClose = () => { + setAnchorEl(null); + }; + + const open = Boolean(anchorEl); + const id = open ? "simple-popover" : undefined; + + return ( + <> + + + + + подсказка + + + + + ); +}; \ No newline at end of file diff --git a/src/ui_kit/Sidebar/Sidebar.tsx b/src/ui_kit/Sidebar/Sidebar.tsx index 6350ea48..b18e668b 100755 --- a/src/ui_kit/Sidebar/Sidebar.tsx +++ b/src/ui_kit/Sidebar/Sidebar.tsx @@ -12,6 +12,7 @@ import { useCurrentQuiz } from "@root/quizes/hooks"; import { useLocation, useNavigate } from "react-router-dom"; import { setCurrentStep } from "@root/quizes/actions"; import { setTryShowAmoTokenExpiredDialog, updateNextStep } from "@root/uiTools/actions"; +import AiPersonalizationIcon from "../../assets/icons/AiPersonalizationIcon"; const quizSettingsMenuItems = [ [TagIcon, "Дополнения"], @@ -168,6 +169,20 @@ export default function Sidebar({ changePage, disableCollapse }: SidebarProps) { /> } /> + { + navigate("/personalization-ai"); + setCurrentStep(17); + setTryShowAmoTokenExpiredDialog(true); + }} + text={"Персонализация вопросов с помощью AI"} + isCollapsed={isMenuCollapsed} + isActive={pathname.startsWith("/personalization-ai")} + disabled={pathname.startsWith("/personalization-ai") ? false : quiz === undefined ? true : quiz?.config.type === null} + icon={ + + } + /> { navigate("/integrations"); From 6273e62e66b4a518b0aeb8f604d3db300546ad58 Mon Sep 17 00:00:00 2001 From: Nastya Date: Fri, 30 May 2025 00:37:58 +0300 Subject: [PATCH 10/43] =?UTF-8?q?=D0=BD=D0=B0=20=D0=B3=D0=BB=D0=B0=D0=B2?= =?UTF-8?q?=D0=BD=D1=83=D1=8E=20=D0=B8=D0=B7=20=D1=83=D1=81=D1=82=D0=B0?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2=D0=BA=D0=B8=20=D0=BA=D0=B2=D0=B8=D0=B7=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/InstallQuiz/InstallQuiz.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/pages/InstallQuiz/InstallQuiz.tsx b/src/pages/InstallQuiz/InstallQuiz.tsx index f344e368..795353ab 100644 --- a/src/pages/InstallQuiz/InstallQuiz.tsx +++ b/src/pages/InstallQuiz/InstallQuiz.tsx @@ -3,8 +3,10 @@ import { decrementCurrentStep } from "@root/quizes/actions"; import ArrowLeft from "@/assets/icons/questionsPage/arrowLeft"; import QuizInstallationCard from "./QuizInstallationCard/QuizInstallationCard"; import QuizLinkCard from "./QuizLinkCard"; +import { useNavigate } from "react-router-dom"; export default function InstallQuiz() { + const navigate = useNavigate(); return ( <> + From c2d79c04cc2e6613cf74eb344630a6d13451e1dd Mon Sep 17 00:00:00 2001 From: Nastya Date: Sun, 1 Jun 2025 17:05:41 +0300 Subject: [PATCH 11/43] =?UTF-8?q?api=20=D1=84=D0=B0=D0=B9=D0=BB=20=D0=B8?= =?UTF-8?q?=20=D0=BE=D1=82=D0=BE=D0=B1=D1=80=D0=B0=D0=B6=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D1=81=D0=BF=D0=B8=D1=81=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api-docs.html | 577 ++++++++++++++++++ src/api/auditory.ts | 106 ++++ src/api/quiz.ts | 4 +- src/pages/PersonalizationAI/AuditoryList.tsx | 114 ++++ .../PersonalizationAI/PersonalizationAI.tsx | 84 +-- 5 files changed, 805 insertions(+), 80 deletions(-) create mode 100644 api-docs.html create mode 100644 src/api/auditory.ts create mode 100644 src/pages/PersonalizationAI/AuditoryList.tsx diff --git a/api-docs.html b/api-docs.html new file mode 100644 index 00000000..d8eff4a6 --- /dev/null +++ b/api-docs.html @@ -0,0 +1,577 @@ + + + + + + QUIZ Service API Documentation + + + +
+
+

QUIZ Service API Documentation

+

Version 1.0.0

+
+
+ + + +
+
+

Components

+ +
+

Quiz Model

+
+
{
+  "id": integer,          // Id of created quiz
+  "qid": string,         // string id for customers
+  "deleted": boolean,    // true if quiz deleted
+  "archived": boolean,   // true if quiz archived
+  "fingerprinting": boolean,  // set true for save deviceId
+  "repeatable": boolean,     // set true for allow user to repeat quiz
+  "note_prevented": boolean, // set true for save statistic of incomplete quiz passing
+  "mail_notifications": boolean, // set true for mail notification for each quiz passing
+  "unique_answers": boolean,    // set true for save statistics only for unique quiz passing
+  "name": string,        // name of quiz. max 280 length
+  "description": string, // description of quiz
+  "config": string,      // config of quiz. serialized json for rules of quiz flow
+  "status": string,      // status of quiz. allow only '', 'draft', 'template', 'stop', 'start'
+  "limit": integer,      // limit is count of max quiz passing
+  "due_to": integer,     // last time when quiz is valid. timestamp in seconds
+  "time_of_passing": integer, // seconds to pass quiz
+  "pausable": boolean,   // true if it is allowed for pause quiz
+  "version": integer,    // version of quiz
+  "version_comment": string, // version comment to version of quiz
+  "parent_ids": integer[], // array of previous versions of quiz
+  "created_at": string,  // time of creating
+  "updated_at": string,  // time of last updating
+  "question_cnt": integer, // count of questions
+  "passed_count": integer, // count passings
+  "average_time": integer, // average time of passing
+  "super": boolean,      // set true if squiz realize group functionality
+  "group_id": integer    // group of new quiz
+}
+
+
+ +
+

Question Model

+
+
{
+  "id": integer,         // Id of created question
+  "quiz_id": integer,    // relation to quiz
+  "title": string,       // title of question. max 512 length
+  "description": string, // description of question
+  "type": string,        // status of question. allow only text, select, file, variant, images, varimg, emoji, date, number, page, rating
+  "required": boolean,   // user must pass this question
+  "deleted": boolean,    // true if question is deleted
+  "page": integer,       // page if question
+  "content": string,     // serialized json of created question
+  "version": integer,    // version of quiz
+  "parent_ids": integer[], // array of previous versions of quiz
+  "created_at": string,  // time of creating
+  "updated_at": string   // time of last updating
+}
+
+
+ +
+

Answer Model

+
+
{
+  "Id": integer,         // id ответа
+  "Content": string,     // контент ответа
+  "QuestionId": integer, // id вопроса к которому ответ
+  "QuizId": integer,     // id опроса к которому ответ
+  "Fingerprint": string, // fingerprint
+  "Session": string,     // сессия
+  "Result": boolean,     // true or false?
+  "CreatedAt": string,   // таймшап когда ответ создан
+  "New": boolean,        // новый ответ?
+  "Deleted": boolean     // удален?
+}
+
+
+ +
+

LeadTarget Model

+
+
{
+  "ID": integer,         // primary key
+  "AccountID": string,   // account identifier
+  "Type": string,        // type of target (mail, telegram, whatsapp)
+  "QuizID": integer,     // ID of the quiz
+  "Target": string,      // target address
+  "InviteLink": string,  // invitation link
+  "Deleted": boolean,    // is deleted
+  "CreatedAt": string    // creation timestamp
+}
+
+
+ +
+

TgAccount Model

+
+
{
+  "ID": integer,         // primary key
+  "ApiID": integer,      // Telegram API ID
+  "ApiHash": string,     // Telegram API Hash
+  "PhoneNumber": string, // phone number
+  "Password": string,    // account password
+  "Status": string,      // account status (active, inactive, ban)
+  "Deleted": boolean,    // is deleted
+  "CreatedAt": string    // creation timestamp
+}
+
+
+
+ +
+

Quiz Endpoints

+ +
+

Create Quiz

+ POST + /quiz/create +

Create a new quiz with specified parameters.

+ +
+

Security

+

This endpoint requires authentication.

+
+ +

Request Body:

+
+
{
+  "fingerprinting": boolean,  // set true for save deviceId
+  "repeatable": boolean,     // set true for allow user to repeat quiz
+  "note_prevented": boolean, // set true for save statistic of incomplete quiz passing
+  "mail_notifications": boolean, // set true for mail notification for each quiz passing
+  "unique_answers": boolean,    // set true for save statistics only for unique quiz passing
+  "name": string,        // name of quiz. max 280 length
+  "description": string, // description of quiz
+  "config": string,      // config of quiz. serialized json for rules of quiz flow
+  "status": string,      // status of quiz. allow only '', 'draft', 'template', 'stop', 'start'
+  "limit": integer,      // limit is count of max quiz passing
+  "due_to": integer,     // last time when quiz is valid. timestamp in seconds
+  "time_of_passing": integer, // seconds to pass quiz
+  "pausable": boolean,   // true if it is allowed for pause quiz
+  "question_cnt": integer, // count of questions
+  "super": boolean,      // set true if squiz realize group functionality
+  "group_id": integer    // group of new quiz
+}
+
+ +

Responses:

+
+
201 Created
+

Quiz successfully created. Returns the created quiz object.

+
+
{
+  "id": integer,
+  "qid": string,
+  "name": string,
+  "description": string,
+  // ... other quiz properties
+}
+
+
+ +
+
422 Unprocessable Entity
+

Name field should have less than 280 characters.

+
+ +
+
406 Not Acceptable
+

Status on creating must be only draft, template, stop, start or due to time must be lesser than now.

+
+ Allowed status values: '', 'draft', 'template', 'stop', 'start' +
+
+ +
+
409 Conflict
+

You can pause quiz only if it has deadline for passing.

+
+ +
+
500 Internal Server Error
+

If you get any content string send it to developer.

+
+
+ +
+

Get Quiz List

+ POST + /quiz/getList +

Get paginated list of quizzes with filtering options.

+ +

Request Body:

+
+
{
+  "limit": integer,
+  "offset": integer,
+  "from": integer,
+  "to": integer,
+  "search": string,
+  "status": string,
+  "deleted": boolean,
+  "archived": boolean,
+  "super": boolean,
+  "group_id": integer
+}
+
+ +

Responses:

+
+
200 OK
+

Returns list of quizzes with total count.

+
+
{
+  "count": integer,
+  "items": [
+    {
+      "id": integer,
+      "qid": string,
+      // ... other quiz properties
+    }
+  ]
+}
+
+
+ +
+
406 Not Acceptable
+

Inappropriate status, allowed only '', 'stop', 'start', 'draft', 'template', 'timeout', 'offlimit'.

+
+ +
+
500 Internal Server Error
+

If you get any content string send it to developer.

+
+
+ + +
+ +
+

Question Endpoints

+ +
+

Create Question

+ POST + /question/create +

Create a new question for a quiz.

+
+ + +
+ +
+

Results Endpoints

+ +
+

Get Quiz Results

+ POST + /results/getResults/{quizId} +

Get list of quiz results with pagination.

+ +

Path Parameters:

+
+ quizId - ID of the quiz to get results for +
+ +

Request Body:

+
+
{
+  "to": integer,         // таймштамп времени, до которого выбирать статистику. если 0 или не передано - этого ограничения нет
+  "from": integer,       // таймштамп времени, после которого выбирать статистику. если 0 или не передано - этого ограничения нет
+  "new": boolean,        // флаг, по которому вернутся только новые результаты, ещё не просмотренные пользователем
+  "page": integer,       // номер страницы для пагинации
+  "limit": integer       // размер страницы для пагинации
+}
+
+ +

Responses:

+
+
200 OK
+

Returns paginated list of results.

+
+
{
+  "total_count": integer,  // общее количество элементов удволетворяющее фильтру
+  "results": [
+    {
+      "content": string,   // содержимое ответа
+      "id": integer,       // айдишник ответа
+      "new": boolean,      // статус, был ли просмотрен ответ
+      "created_at": string // время создания этого результата
+    }
+  ]
+}
+
+
+
+ +
+

Export Results

+ POST + /results/{quizID}/export +

Export quiz results to CSV format.

+ +

Path Parameters:

+
+ quizID - ID of the quiz to export results from +
+ +

Request Body:

+
+
{
+  "to": string,          // Дата окончания диапазона времени для экспорта результатов
+  "from": string,        // Дата начала временного диапазона для экспорта результатов
+  "new": boolean         // Экспортировать ли только новые результаты?
+}
+
+ +

Responses:

+
+
200 OK
+

Returns CSV file with quiz results.

+
+
Content-Type: text/csv
+
+
+
+
+ +
+

Telegram Endpoints

+ +
+

Create Telegram Account

+ POST + /telegram/create +

Authorize server in Telegram account.

+ +

Request Body:

+
+
{
+  "ApiID": integer,      // Telegram API ID
+  "ApiHash": string,     // Telegram API Hash
+  "PhoneNumber": string, // Phone number
+  "Password": string     // Account password
+}
+
+ +

Responses:

+
+
200 OK
+

Returns signature for code verification.

+
+
{
+  "signature": string    // Session identifier for code verification
+}
+
+
+ +
+
409 Conflict
+

Account already exists and is active.

+
+
+
+ +
+

Audience Endpoints

+ +
+

Create Quiz Audience

+ POST + /quiz/{quizID}/auditory +

Create audience for a quiz.

+ +

Path Parameters:

+
+ quizID - ID of the quiz +
+ +

Responses:

+
+
200 OK
+

Returns ID of created audience.

+
+
{
+  "id": integer    // ID of created auditory
+}
+
+
+
+
+ +
+

Statistics Endpoints

+ +
+

Get Question Statistics

+ POST + /statistic/{quizID}/questions +

Get statistics for specific questions in a quiz.

+
+ + +
+ +
+

Account Endpoints

+ +
+

Add Lead Target

+ POST + /account/leadtarget +

Add a target destination for lead notifications.

+
+ + +
+
+ +
+

© 2024 QUIZ Service API Documentation

+
+ + \ No newline at end of file diff --git a/src/api/auditory.ts b/src/api/auditory.ts new file mode 100644 index 00000000..77a2a705 --- /dev/null +++ b/src/api/auditory.ts @@ -0,0 +1,106 @@ +import { makeRequest } from "@frontend/kitui"; +import { parseAxiosError } from "@utils/parse-error"; + +const API_URL = `${process.env.REACT_APP_DOMAIN}/squiz`; + +// Types +export interface AuditoryItem { + id: number; + quiz_id: number; + sex: boolean; + age: string; + deleted: boolean; + created_at: number; +} + +export interface AuditoryResponse { + data: AuditoryItem[]; +} + +// Request Types +export interface AuditoryGetRequest { + quizId: number; +} + +export interface AuditoryDeleteRequest { + id: number; +} + +export interface AuditoryAddRequest { + sex: boolean; + age: string; +} + +// Parameters +export interface AuditoryGetParams { + quizId: number; +} + +export interface AuditoryDeleteParams { + quizId: number; + auditoryId: number; +} + +export interface AuditoryAddParams { + quizId: number; + body: AuditoryAddRequest; +} + +// API calls +export const auditoryGet = async ({ quizId }: AuditoryGetParams): Promise<[AuditoryResponse | null, string?]> => { + if (!quizId) { + return [null, "Quiz ID is required"]; + } + + try { + const response = await makeRequest({ + url: `${API_URL}/quiz/${quizId}/auditory`, + method: "GET", + }); + + return [response]; + } catch (nativeError) { + const [error] = parseAxiosError(nativeError); + return [null, `Не удалось получить аудиторию. ${error}`]; + } +}; + +export const auditoryDelete = async ({ quizId, auditoryId }: AuditoryDeleteParams): Promise<[AuditoryResponse | null, string?]> => { + if (!quizId || !auditoryId) { + return [null, "Quiz ID and Auditory ID are required"]; + } + + try { + const response = await makeRequest({ + url: `${API_URL}/quiz/${quizId}/auditory`, + body: { + id: auditoryId + }, + method: "DELETE", + }); + + return [response]; + } catch (nativeError) { + const [error] = parseAxiosError(nativeError); + return [null, `Не удалось удалить аудиторию. ${error}`]; + } +}; + +export const auditoryAdd = async ({ quizId, body }: AuditoryAddParams): Promise<[AuditoryResponse | null, string?]> => { + if (!quizId) { + return [null, "Quiz ID is required"]; + } + + try { + const response = await makeRequest({ + url: `${API_URL}/quiz/${quizId}/auditory`, + body, + method: "POST", + }); + + return [response]; + } catch (nativeError) { + const [error] = parseAxiosError(nativeError); + return [null, `Не удалось добавить аудиторию. ${error}`]; + } +}; \ No newline at end of file diff --git a/src/api/quiz.ts b/src/api/quiz.ts index f43c3f06..1bcea534 100644 --- a/src/api/quiz.ts +++ b/src/api/quiz.ts @@ -148,8 +148,8 @@ export const addQuizImages = async ( const name = image?.name ? transliterate(image?.name.replace(/\s/g, '_')) : "blob" //Замена всех побелов на _ - const renamedImage = new File([image], name) - + const renamedImage = new File([image], name) + formData.append("quiz", quizId.toString()); formData.append("image", renamedImage); diff --git a/src/pages/PersonalizationAI/AuditoryList.tsx b/src/pages/PersonalizationAI/AuditoryList.tsx new file mode 100644 index 00000000..b9e26d49 --- /dev/null +++ b/src/pages/PersonalizationAI/AuditoryList.tsx @@ -0,0 +1,114 @@ +import { auditoryGet, AuditoryResponse, AuditoryItem } from "@/api/auditory"; +import ArrowDownIcon from "@/assets/icons/ArrowDownIcon"; +import CopyIcon from "@/assets/icons/CopyIcon"; +import { useCurrentQuiz } from "@/stores/quizes/hooks"; +import { InfoPopover } from "@/ui_kit/InfoPopover"; +import { useDomainDefine } from "@/utils/hooks/useDomainDefine"; +import { Box, Collapse, IconButton, List, ListItem, Typography, useTheme } from "@mui/material"; +import { useEffect, useState } from "react"; + +const PURPLE = "#7E2AEA"; + +export const AuditoryList = () => { + const theme = useTheme(); + const quiz = useCurrentQuiz(); + const { isTestServer } = useDomainDefine(); + const [linksOpen, setLinksOpen] = useState(true); + const [auditory, setAuditory] = useState([]); + + const handleCopy = (text: string) => { + navigator.clipboard.writeText(text); + }; + + useEffect(() => { + (async () => { + if (quiz?.backendId) { + const [result, error] = await auditoryGet({ quizId: quiz.backendId }); + console.log("result-___---_------__---__-__---_------__---__-__---_------__---__-__---_------__---__-____--__") + console.log(result) + if (result) { + setAuditory(result); + } + } + })(); + }, [quiz]); + + console.log("auditory-___---_auditory__---__-__auditory_------__---__-__---_------__---__-__---_------__---__-____--__") + console.log(auditory) + + return ( + <> + + + + Ваши сохраненные ссылки + + setLinksOpen((prev) => !prev)} + size="large" + > + + + + + + {auditory.map((item, idx) => { + const linkText = `${isTestServer ? "https://s.hbpn.link/" : "https://hbpn.link/"}?_paud=${item.id}`; + console.log(item) + return ( + + + + + handleCopy(linkText)} + > + + + + } + > + + {linkText} + + + ); + })} + + + + + ); +}; \ No newline at end of file diff --git a/src/pages/PersonalizationAI/PersonalizationAI.tsx b/src/pages/PersonalizationAI/PersonalizationAI.tsx index 80331c4a..bd7fc388 100644 --- a/src/pages/PersonalizationAI/PersonalizationAI.tsx +++ b/src/pages/PersonalizationAI/PersonalizationAI.tsx @@ -2,24 +2,20 @@ import { Box, Container, Typography, TextField, Button, List, ListItem, IconButt import { InfoPopover } from '@ui_kit/InfoPopover'; import CopyIcon from "@/assets/icons/CopyIcon"; import GenderAndAgeSelector from "./GenderAndAgeSelector"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import CustomTextField from "@ui_kit/CustomTextField"; import Collapse from '@mui/material/Collapse'; import { ArrowDownIcon } from "../../assets/icons/questionsPage/ArrowDownIcon"; import { useTheme } from "@mui/material"; +import { auditoryAdd, auditoryGet } from "@/api/auditory"; +import { useCurrentQuiz } from "@/stores/quizes/hooks"; +import { AuditoryList } from "./AuditoryList"; const PURPLE = "#7E2AEA"; -const GREY_TEXT = "#A0A0A0"; -const GREY_BORDER = "#E0E0E0"; -const GREY_ICON = "#B0B0B0"; -const BLOCK_RADIUS = "16px"; -const BLOCK_PX = "32px"; -const BLOCK_PY = "24px"; export default function PersonalizationAI() { - const [gender, setGender] = useState(''); - const [linksOpen, setLinksOpen] = useState(true); const theme = useTheme(); + const [gender, setGender] = useState(''); return ( @@ -47,9 +43,6 @@ export default function PersonalizationAI() { }}> - - - {/* Ссылка */} @@ -95,73 +88,8 @@ export default function PersonalizationAI() { - {/* Второй белый блок */} - - - - Ваши сохраненные ссылки - - setLinksOpen((prev) => !prev)} - size="large" - > - - - - - - {[1, 2, 3, 4, 5].map((_, idx) => ( - - - - - + - - - - } - > - - linkexample.ru - - - ))} - - - ); } From e7121cb06a0aeeb09118902be032242b48433569 Mon Sep 17 00:00:00 2001 From: Nastya Date: Mon, 2 Jun 2025 00:27:22 +0300 Subject: [PATCH 12/43] =?UTF-8?q?=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=B1=D0=B5=D0=B7=20=D1=80=D0=B5=D0=B0=D0=BA?= =?UTF-8?q?=D1=82=D0=B8=D0=B2=D0=BD=D0=BE=D1=81=D1=82=D0=B8,=20=D0=B2?= =?UTF-8?q?=D1=8B=D0=B2=D0=B5=D0=B4=D0=B5=D0=BD=20=D0=BA=D0=BE=D1=80=D1=80?= =?UTF-8?q?=D0=B5=D0=BA=D1=82=D0=BD=D1=8B=D0=B9=20=D1=81=D0=BF=D0=B8=D1=81?= =?UTF-8?q?=D0=BE=D0=BA=20=D0=BB=D0=B8=D0=BD=D0=BA=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/auditory.ts | 9 +- src/pages/PersonalizationAI/AuditoryLink.tsx | 74 ++++++++ src/pages/PersonalizationAI/AuditoryList.tsx | 77 +-------- .../GenderAndAgeSelector.tsx | 18 +- .../PersonalizationAI/PersonalizationAI.tsx | 158 +++++++++++------- src/ui_kit/InfoPopover.tsx | 16 +- src/ui_kit/Toolbars/TooltipClickInfo.tsx | 4 + 7 files changed, 212 insertions(+), 144 deletions(-) create mode 100644 src/pages/PersonalizationAI/AuditoryLink.tsx diff --git a/src/api/auditory.ts b/src/api/auditory.ts index 77a2a705..f0ca4914 100644 --- a/src/api/auditory.ts +++ b/src/api/auditory.ts @@ -47,13 +47,13 @@ export interface AuditoryAddParams { } // API calls -export const auditoryGet = async ({ quizId }: AuditoryGetParams): Promise<[AuditoryResponse | null, string?]> => { +export const auditoryGet = async ({ quizId }: AuditoryGetParams): Promise<[AuditoryItem[] | null, string?]> => { if (!quizId) { return [null, "Quiz ID is required"]; } try { - const response = await makeRequest({ + const response = await makeRequest({ url: `${API_URL}/quiz/${quizId}/auditory`, method: "GET", }); @@ -72,10 +72,7 @@ export const auditoryDelete = async ({ quizId, auditoryId }: AuditoryDeleteParam try { const response = await makeRequest({ - url: `${API_URL}/quiz/${quizId}/auditory`, - body: { - id: auditoryId - }, + url: `${API_URL}/quiz/${quizId}/auditory/${auditoryId}`, method: "DELETE", }); diff --git a/src/pages/PersonalizationAI/AuditoryLink.tsx b/src/pages/PersonalizationAI/AuditoryLink.tsx new file mode 100644 index 00000000..57cf9fd0 --- /dev/null +++ b/src/pages/PersonalizationAI/AuditoryLink.tsx @@ -0,0 +1,74 @@ +import { AuditoryItem } from "@/api/auditory"; +import CopyIcon from "@/assets/icons/CopyIcon"; +import Trash from "@/assets/icons/trash"; +import { InfoPopover } from "@/ui_kit/InfoPopover"; +import TooltipClickInfo from "@/ui_kit/Toolbars/TooltipClickInfo"; +import { useDomainDefine } from "@/utils/hooks/useDomainDefine"; +import { IconButton, ListItem, Typography, useTheme } from "@mui/material"; + +interface AuditoryLinkProps { + item: AuditoryItem; + index: number; + deleteModal: (id:number) => void +} + +export const AuditoryLink = ({ item, index, deleteModal }: AuditoryLinkProps) => { + const theme = useTheme(); + const { isTestServer } = useDomainDefine(); + + const handleCopy = (text: string) => { + navigator.clipboard.writeText(text); + }; + + const linkText = `${isTestServer ? "https://s.hbpn.link/" : "https://hbpn.link/"}?_paud=${item.id}`; + + return ( + + deleteModal(item.id)} edge="end" aria-label="info" sx={{ color: theme.palette.brightPurple.main, p: 0, width: 18, height: 18 }}> + + + + + + handleCopy(linkText)} + > + + + + } + > + + {linkText} + + + ); +}; \ No newline at end of file diff --git a/src/pages/PersonalizationAI/AuditoryList.tsx b/src/pages/PersonalizationAI/AuditoryList.tsx index b9e26d49..91410ab4 100644 --- a/src/pages/PersonalizationAI/AuditoryList.tsx +++ b/src/pages/PersonalizationAI/AuditoryList.tsx @@ -1,37 +1,17 @@ import { auditoryGet, AuditoryResponse, AuditoryItem } from "@/api/auditory"; import ArrowDownIcon from "@/assets/icons/ArrowDownIcon"; -import CopyIcon from "@/assets/icons/CopyIcon"; import { useCurrentQuiz } from "@/stores/quizes/hooks"; -import { InfoPopover } from "@/ui_kit/InfoPopover"; import { useDomainDefine } from "@/utils/hooks/useDomainDefine"; -import { Box, Collapse, IconButton, List, ListItem, Typography, useTheme } from "@mui/material"; +import { Box, Collapse, IconButton, List, Typography, useTheme } from "@mui/material"; import { useEffect, useState } from "react"; +import { AuditoryLink } from "./AuditoryLink"; -const PURPLE = "#7E2AEA"; -export const AuditoryList = () => { +export const AuditoryList = ({auditory, deleteModal}:{auditory:AuditoryItem[], deleteModal:(id:number) => void}) => { const theme = useTheme(); - const quiz = useCurrentQuiz(); const { isTestServer } = useDomainDefine(); const [linksOpen, setLinksOpen] = useState(true); - const [auditory, setAuditory] = useState([]); - const handleCopy = (text: string) => { - navigator.clipboard.writeText(text); - }; - - useEffect(() => { - (async () => { - if (quiz?.backendId) { - const [result, error] = await auditoryGet({ quizId: quiz.backendId }); - console.log("result-___---_------__---__-__---_------__---__-__---_------__---__-__---_------__---__-____--__") - console.log(result) - if (result) { - setAuditory(result); - } - } - })(); - }, [quiz]); console.log("auditory-___---_auditory__---__-__auditory_------__---__-__---_------__---__-__---_------__---__-____--__") console.log(auditory) @@ -51,7 +31,7 @@ export const AuditoryList = () => { Ваши сохраненные ссылки setLinksOpen((prev) => !prev)} size="large" > @@ -60,52 +40,9 @@ export const AuditoryList = () => { - {auditory.map((item, idx) => { - const linkText = `${isTestServer ? "https://s.hbpn.link/" : "https://hbpn.link/"}?_paud=${item.id}`; - console.log(item) - return ( - - - - - handleCopy(linkText)} - > - - - - } - > - - {linkText} - - - ); - })} + {auditory.map((item, idx) => ( + + ))} diff --git a/src/pages/PersonalizationAI/GenderAndAgeSelector.tsx b/src/pages/PersonalizationAI/GenderAndAgeSelector.tsx index f3aff559..d6aae39f 100644 --- a/src/pages/PersonalizationAI/GenderAndAgeSelector.tsx +++ b/src/pages/PersonalizationAI/GenderAndAgeSelector.tsx @@ -1,4 +1,4 @@ -import { Box, FormControl, FormLabel, RadioGroup, FormControlLabel, Radio, Select, MenuItem, useTheme } from "@mui/material"; +import { Box, FormControl, FormLabel, RadioGroup, FormControlLabel, Radio, Select, MenuItem, useTheme, Button } from "@mui/material"; import { InfoPopover } from '@ui_kit/InfoPopover'; import CheckboxIcon from "@icons/Checkbox"; @@ -7,6 +7,7 @@ interface GenderAndAgeSelectorProps { setGender: (gender: string) => void; } + export default function GenderAndAgeSelector({ gender, setGender }: GenderAndAgeSelectorProps) { const theme = useTheme(); return ( @@ -167,6 +168,21 @@ export default function GenderAndAgeSelector({ gender, setGender }: GenderAndAge + ); } \ No newline at end of file diff --git a/src/pages/PersonalizationAI/PersonalizationAI.tsx b/src/pages/PersonalizationAI/PersonalizationAI.tsx index bd7fc388..f11916ec 100644 --- a/src/pages/PersonalizationAI/PersonalizationAI.tsx +++ b/src/pages/PersonalizationAI/PersonalizationAI.tsx @@ -1,4 +1,4 @@ -import { Box, Container, Typography, TextField, Button, List, ListItem, IconButton } from "@mui/material"; +import { Box, Container, Typography, TextField, Button, List, ListItem, IconButton, Modal } from "@mui/material"; import { InfoPopover } from '@ui_kit/InfoPopover'; import CopyIcon from "@/assets/icons/CopyIcon"; import GenderAndAgeSelector from "./GenderAndAgeSelector"; @@ -7,60 +7,80 @@ import CustomTextField from "@ui_kit/CustomTextField"; import Collapse from '@mui/material/Collapse'; import { ArrowDownIcon } from "../../assets/icons/questionsPage/ArrowDownIcon"; import { useTheme } from "@mui/material"; -import { auditoryAdd, auditoryGet } from "@/api/auditory"; +import { AuditoryItem, auditoryAdd, auditoryDelete, auditoryGet } from "@/api/auditory"; import { useCurrentQuiz } from "@/stores/quizes/hooks"; import { AuditoryList } from "./AuditoryList"; -const PURPLE = "#7E2AEA"; export default function PersonalizationAI() { const theme = useTheme(); const [gender, setGender] = useState(''); + const [auditory, setAuditory] = useState([]); + const [deleteModal, setDeleteModal] = useState(0); + const quiz = useCurrentQuiz(); + + useEffect(() => { + (async () => { + if (quiz?.backendId) { + const [result, error] = await auditoryGet({ quizId: quiz.backendId }); + console.log("result-___---_------__---__-__---_------__---__-__---_------__---__-__---_------__---__-____--__") + console.log(result) + if (result) { + setAuditory(result); + } + } + })(); + }, [quiz]); + + const handleDelete = () => { + setDeleteModal(0) + auditoryDelete({ quizId: quiz?.backendId, auditoryId: deleteModal }) + } return ( - - - Персонализация вопросов с помощью AI - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit. sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. - + <> + + + Персонализация вопросов с помощью AI + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. + - {/* Первый белый блок */} - - + {/* Первый белый блок */} + + - {/* Ссылка */} - - - Ссылка - - - - Вставьте ссылку со всеми utm-метками - - + {/* Ссылка */} + + + Ссылка + + + + Вставьте ссылку со всеми utm-метками + - - - + - + + setDeleteModal(0)} + aria-labelledby="modal-modal-title" + aria-describedby="modal-modal-description" + > + + Уверены, что хотите удалить ссылку? + + + + + ); } diff --git a/src/ui_kit/InfoPopover.tsx b/src/ui_kit/InfoPopover.tsx index 8ce59e2e..a28b9e67 100644 --- a/src/ui_kit/InfoPopover.tsx +++ b/src/ui_kit/InfoPopover.tsx @@ -1,9 +1,17 @@ -import { useState, MouseEvent } from "react"; +import { useState, MouseEvent, ReactNode } from "react"; import Info from "@icons/Info"; import { Paper, Popover, SxProps, Typography } from "@mui/material"; -export const InfoPopover = ({ blink = false, sx }: {blink?: boolean, sx?: SxProps}) => { +export const InfoPopover = ({ + blink = false, + sx, + children = "подсказка" +}: { + blink?: boolean, + sx?: SxProps, + children?: ReactNode +}) => { const [anchorEl, setAnchorEl] = useState(null); const handleClick = (event: MouseEvent) => { @@ -43,9 +51,7 @@ export const InfoPopover = ({ blink = false, sx }: {blink?: boolean, sx?: SxProp flexDirection: "column", }} > - - подсказка - + {children} diff --git a/src/ui_kit/Toolbars/TooltipClickInfo.tsx b/src/ui_kit/Toolbars/TooltipClickInfo.tsx index b95f5384..c8f2f353 100644 --- a/src/ui_kit/Toolbars/TooltipClickInfo.tsx +++ b/src/ui_kit/Toolbars/TooltipClickInfo.tsx @@ -26,6 +26,10 @@ export default function TooltipClickInfo({ title }: { title: string }) { disableFocusListener disableHoverListener disableTouchListener + sx={{ + fontSize: "12px", + p:"10px" + }} title={title} > From 1e8a50077b6dc4824c6525742f43463016207129 Mon Sep 17 00:00:00 2001 From: Nastya Date: Mon, 2 Jun 2025 00:36:55 +0300 Subject: [PATCH 13/43] =?UTF-8?q?=D1=80=D0=B5=D0=B0=D0=BA=D1=82=D0=B8?= =?UTF-8?q?=D0=B2=D0=BD=D0=BE=D0=B5=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/PersonalizationAI/AuditoryLink.tsx | 26 +++++++---- src/pages/PersonalizationAI/AuditoryList.tsx | 6 +-- .../PersonalizationAI/PersonalizationAI.tsx | 46 +++++++++++++++++-- 3 files changed, 61 insertions(+), 17 deletions(-) diff --git a/src/pages/PersonalizationAI/AuditoryLink.tsx b/src/pages/PersonalizationAI/AuditoryLink.tsx index 57cf9fd0..e0cbe976 100644 --- a/src/pages/PersonalizationAI/AuditoryLink.tsx +++ b/src/pages/PersonalizationAI/AuditoryLink.tsx @@ -2,17 +2,16 @@ import { AuditoryItem } from "@/api/auditory"; import CopyIcon from "@/assets/icons/CopyIcon"; import Trash from "@/assets/icons/trash"; import { InfoPopover } from "@/ui_kit/InfoPopover"; -import TooltipClickInfo from "@/ui_kit/Toolbars/TooltipClickInfo"; import { useDomainDefine } from "@/utils/hooks/useDomainDefine"; import { IconButton, ListItem, Typography, useTheme } from "@mui/material"; interface AuditoryLinkProps { item: AuditoryItem; index: number; - deleteModal: (id:number) => void + onDelete: (id: number) => void; } -export const AuditoryLink = ({ item, index, deleteModal }: AuditoryLinkProps) => { +export const AuditoryLink = ({ item, index, onDelete }: AuditoryLinkProps) => { const theme = useTheme(); const { isTestServer } = useDomainDefine(); @@ -20,6 +19,10 @@ export const AuditoryLink = ({ item, index, deleteModal }: AuditoryLinkProps) => navigator.clipboard.writeText(text); }; + const handleDelete = () => { + onDelete(item.id); + }; + const linkText = `${isTestServer ? "https://s.hbpn.link/" : "https://hbpn.link/"}?_paud=${item.id}`; return ( @@ -39,13 +42,18 @@ export const AuditoryLink = ({ item, index, deleteModal }: AuditoryLinkProps) => display: 'flex', alignItems: 'center', gap: '12px', - width: "70px", + width: "60px", justifyContent: "space-between", }, }} secondaryAction={ <> - deleteModal(item.id)} edge="end" aria-label="info" sx={{ color: theme.palette.brightPurple.main, p: 0, width: 18, height: 18 }}> + }} /> - + - handleCopy(linkText)} > diff --git a/src/pages/PersonalizationAI/AuditoryList.tsx b/src/pages/PersonalizationAI/AuditoryList.tsx index 91410ab4..667904d5 100644 --- a/src/pages/PersonalizationAI/AuditoryList.tsx +++ b/src/pages/PersonalizationAI/AuditoryList.tsx @@ -6,13 +6,11 @@ import { Box, Collapse, IconButton, List, Typography, useTheme } from "@mui/mate import { useEffect, useState } from "react"; import { AuditoryLink } from "./AuditoryLink"; - -export const AuditoryList = ({auditory, deleteModal}:{auditory:AuditoryItem[], deleteModal:(id:number) => void}) => { +export const AuditoryList = ({auditory, onDelete}:{auditory:AuditoryItem[], onDelete: (id: number) => void}) => { const theme = useTheme(); const { isTestServer } = useDomainDefine(); const [linksOpen, setLinksOpen] = useState(true); - console.log("auditory-___---_auditory__---__-__auditory_------__---__-__---_------__---__-__---_------__---__-____--__") console.log(auditory) @@ -41,7 +39,7 @@ export const AuditoryList = ({auditory, deleteModal}:{auditory:AuditoryItem[], d {auditory.map((item, idx) => ( - + ))} diff --git a/src/pages/PersonalizationAI/PersonalizationAI.tsx b/src/pages/PersonalizationAI/PersonalizationAI.tsx index f11916ec..9330b162 100644 --- a/src/pages/PersonalizationAI/PersonalizationAI.tsx +++ b/src/pages/PersonalizationAI/PersonalizationAI.tsx @@ -10,6 +10,7 @@ import { useTheme } from "@mui/material"; import { AuditoryItem, auditoryAdd, auditoryDelete, auditoryGet } from "@/api/auditory"; import { useCurrentQuiz } from "@/stores/quizes/hooks"; import { AuditoryList } from "./AuditoryList"; +import { useSnackbar } from "notistack"; export default function PersonalizationAI() { @@ -18,6 +19,7 @@ export default function PersonalizationAI() { const [auditory, setAuditory] = useState([]); const [deleteModal, setDeleteModal] = useState(0); const quiz = useCurrentQuiz(); + const { enqueueSnackbar } = useSnackbar(); useEffect(() => { (async () => { @@ -32,9 +34,45 @@ export default function PersonalizationAI() { })(); }, [quiz]); - const handleDelete = () => { - setDeleteModal(0) - auditoryDelete({ quizId: quiz?.backendId, auditoryId: deleteModal }) + const handleDelete = async () => { + // 1. Закрываем модалку + setDeleteModal(0); + + // 2. Находим индекс объекта в стейте + const indexToDelete = auditory.findIndex(item => item.id === deleteModal); + if (indexToDelete === -1) return; + + // 3. Сохраняем удаляемый объект + const deletedItem = auditory[indexToDelete]; + + // 4. Меняем стейт, вырезая объект + setAuditory(prev => prev.filter(item => item.id !== deleteModal)); + + try { + // 5. Вызываем функцию удаления + const [result, error] = await auditoryDelete({ + quizId: quiz?.backendId, + auditoryId: deleteModal + }); + + if (error) { + // 6. Если удалить не удалось - показываем снекбар и возвращаем ссылку + enqueueSnackbar('Не удалось удалить ссылку', { variant: 'error' }); + setAuditory(prev => { + const newArray = [...prev]; + newArray.splice(indexToDelete, 0, deletedItem); + return newArray; + }); + } + } catch (error) { + // Обработка ошибки сети или других ошибок + enqueueSnackbar('Произошла ошибка при удалении', { variant: 'error' }); + setAuditory(prev => { + const newArray = [...prev]; + newArray.splice(indexToDelete, 0, deletedItem); + return newArray; + }); + } } return ( @@ -92,7 +130,7 @@ export default function PersonalizationAI() { - + Date: Mon, 2 Jun 2025 01:02:43 +0300 Subject: [PATCH 14/43] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=B8=D1=82=D0=B5=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/PersonalizationAI/AuditoryLink.tsx | 5 +- .../GenderAndAgeSelector.tsx | 374 ++++++++++-------- .../PersonalizationAI/PersonalizationAI.tsx | 12 +- 3 files changed, 218 insertions(+), 173 deletions(-) diff --git a/src/pages/PersonalizationAI/AuditoryLink.tsx b/src/pages/PersonalizationAI/AuditoryLink.tsx index e0cbe976..9264d420 100644 --- a/src/pages/PersonalizationAI/AuditoryLink.tsx +++ b/src/pages/PersonalizationAI/AuditoryLink.tsx @@ -2,6 +2,7 @@ import { AuditoryItem } from "@/api/auditory"; import CopyIcon from "@/assets/icons/CopyIcon"; import Trash from "@/assets/icons/trash"; import { InfoPopover } from "@/ui_kit/InfoPopover"; +import TooltipClickInfo from "@/ui_kit/Toolbars/TooltipClickInfo"; import { useDomainDefine } from "@/utils/hooks/useDomainDefine"; import { IconButton, ListItem, Typography, useTheme } from "@mui/material"; @@ -42,7 +43,7 @@ export const AuditoryLink = ({ item, index, onDelete }: AuditoryLinkProps) => { display: 'flex', alignItems: 'center', gap: '12px', - width: "60px", + width: "70px", justifyContent: "space-between", }, }} @@ -61,7 +62,7 @@ export const AuditoryLink = ({ item, index, onDelete }: AuditoryLinkProps) => { }} /> - + void; + handleAdd: (item: any) => void; } - -export default function GenderAndAgeSelector({ gender, setGender }: GenderAndAgeSelectorProps) { +export default function GenderAndAgeSelector({ handleAdd }: GenderAndAgeSelectorProps) { const theme = useTheme(); + const [age, setAge] = useState(''); + const [gender, setGender] = useState(''); + const quiz = useCurrentQuiz(); + const { enqueueSnackbar } = useSnackbar(); + + const isFormValid = gender && age; + + const addItem = async () => { + if (!quiz?.backendId) { + enqueueSnackbar('Ошибка: не выбран квиз', { variant: 'error' }); + return; + } + + try { + const [result, error] = await auditoryAdd({ + quizId: quiz.backendId, + body: { + sex: gender === "male", + age + } + }); + + if (error) { + enqueueSnackbar('Не удалось добавить ссылку', { variant: 'error' }); + return; + } + + if (result) { + handleAdd({ + id: result.ID, + quiz_id: quiz.backendId, + sex: gender === "male", + age, + deleted: false, + }); + enqueueSnackbar('Ссылка успешно добавлена', { variant: 'success' }); + // Очищаем форму + setGender(''); + setAge(''); + } + } catch (error) { + enqueueSnackbar('Произошла ошибка при добавлении', { variant: 'error' }); + } + }; + return ( - + + - - - - - + + Пол + + + setGender(e.target.value)} + > + } checkedIcon={} />} + label="М" + /> + } checkedIcon={} />} + label="Ж" + /> + + + + + + Пол - - - setGender(e.target.value)}> - - Возраст + + + + + - value="male" control={} checkedIcon={} />} label="М" /> - } checkedIcon={} />} label="Ж" /> - - - - - - - - Возраст - - - - - + ); } \ No newline at end of file diff --git a/src/pages/PersonalizationAI/PersonalizationAI.tsx b/src/pages/PersonalizationAI/PersonalizationAI.tsx index 9330b162..b2686e52 100644 --- a/src/pages/PersonalizationAI/PersonalizationAI.tsx +++ b/src/pages/PersonalizationAI/PersonalizationAI.tsx @@ -1,11 +1,8 @@ import { Box, Container, Typography, TextField, Button, List, ListItem, IconButton, Modal } from "@mui/material"; import { InfoPopover } from '@ui_kit/InfoPopover'; -import CopyIcon from "@/assets/icons/CopyIcon"; import GenderAndAgeSelector from "./GenderAndAgeSelector"; import { useEffect, useState } from "react"; import CustomTextField from "@ui_kit/CustomTextField"; -import Collapse from '@mui/material/Collapse'; -import { ArrowDownIcon } from "../../assets/icons/questionsPage/ArrowDownIcon"; import { useTheme } from "@mui/material"; import { AuditoryItem, auditoryAdd, auditoryDelete, auditoryGet } from "@/api/auditory"; import { useCurrentQuiz } from "@/stores/quizes/hooks"; @@ -15,7 +12,6 @@ import { useSnackbar } from "notistack"; export default function PersonalizationAI() { const theme = useTheme(); - const [gender, setGender] = useState(''); const [auditory, setAuditory] = useState([]); const [deleteModal, setDeleteModal] = useState(0); const quiz = useCurrentQuiz(); @@ -75,9 +71,13 @@ export default function PersonalizationAI() { } } + const handleAdd = (item:AuditoryItem) => { + setAuditory(old => ([...old, item])) + } + return ( <> - + Персонализация вопросов с помощью AI @@ -100,7 +100,7 @@ export default function PersonalizationAI() { boxShadow: "none", maxWidth: "796px" }}> - + {/* Ссылка */} From 65db81af2d028c9bddf935377792c16b2b03c80d Mon Sep 17 00:00:00 2001 From: Nastya Date: Mon, 2 Jun 2025 01:32:35 +0300 Subject: [PATCH 15/43] =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D1=8E=20=D0=B2=20?= =?UTF-8?q?=D1=85=D0=B5=D0=B4=D0=B5=D1=80=D0=B5=20=D1=81=D0=BA=D1=80=D0=BE?= =?UTF-8?q?=D0=BB=D0=BB=D0=B8=D1=82=D1=81=D1=8F,=20=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D1=8E=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/PersonalizationAI/GenderAndAgeSelector.tsx | 2 +- src/ui_kit/MenuItem.tsx | 1 + src/ui_kit/Sidebar/Sidebar.tsx | 11 +++++++---- src/ui_kit/Sidebar/SidebarModal/index.tsx | 2 +- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/pages/PersonalizationAI/GenderAndAgeSelector.tsx b/src/pages/PersonalizationAI/GenderAndAgeSelector.tsx index cc207d33..b79cc3c3 100644 --- a/src/pages/PersonalizationAI/GenderAndAgeSelector.tsx +++ b/src/pages/PersonalizationAI/GenderAndAgeSelector.tsx @@ -211,7 +211,7 @@ export default function GenderAndAgeSelector({ handleAdd }: GenderAndAgeSelector - + ); } \ No newline at end of file From 8255fe6908817657cfe205ec42f5d1f65ec6af57 Mon Sep 17 00:00:00 2001 From: Nastya Date: Tue, 3 Jun 2025 21:07:37 +0300 Subject: [PATCH 22/43] =?UTF-8?q?=D0=BA=D0=BE=D1=80=D1=80=D0=B5=D0=BA?= =?UTF-8?q?=D1=82=D0=BD=D1=8B=D0=B5=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D0=BA=D0=B8=20=D1=81=D0=B5=D0=BB=D0=B5=D0=BA=D1=82=D0=B0=20?= =?UTF-8?q?=D0=B2=D0=BE=D0=B7=D1=80=D0=B0=D1=81=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PersonalizationAI/AgeInputWithSelect.tsx | 51 ++++++++++++++++++- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/src/pages/PersonalizationAI/AgeInputWithSelect.tsx b/src/pages/PersonalizationAI/AgeInputWithSelect.tsx index 3901310a..f7125098 100644 --- a/src/pages/PersonalizationAI/AgeInputWithSelect.tsx +++ b/src/pages/PersonalizationAI/AgeInputWithSelect.tsx @@ -10,7 +10,8 @@ import { Grow, ClickAwayListener, MenuList, - useTheme + useTheme, + FormHelperText } from '@mui/material'; import ArrowDownIcon from "@/assets/icons/ArrowDownIcon"; @@ -23,13 +24,47 @@ const AgeInputWithSelect = ({ value, onChange }: AgeInputWithSelectProps) => { const theme = useTheme(); const [open, setOpen] = useState(false); const anchorRef = useRef(null); + const [errorType, setErrorType] = useState<'format' | 'range' | false>(false); + + // Валидация: только число или диапазон число-число, и диапазон 0-150 + const validate = (val: string) => { + if (!val) return false; + // Число (только положительное) + if (/^\d+$/.test(val)) { + const num = Number(val); + if (num < 0 || num > 150) return 'range'; + return false; + } + // Диапазон (только положительные числа) + const rangeMatch = val.match(/^(\d+)-(\d+)$/); + if (rangeMatch) { + const left = Number(rangeMatch[1]); + const right = Number(rangeMatch[2]); + if (left < 0 || left > 150 || right < 0 || right > 150 || left > right) return 'range'; + return false; + } + // Если есть минус не в начале диапазона — это ошибка диапазона + if (/^-?\d+-\d+$/.test(val) || /^\d+-\d+-\d+$/.test(val)) { + return 'range'; + } + return 'format'; + }; const handleInputChange = (e: React.ChangeEvent) => { - onChange(e.target.value); + const filtered = e.target.value.replace(/[^\d-]/g, ''); + onChange(filtered); + setErrorType(false); + }; + + const handleInputBlur = (e: React.FocusEvent) => { + const trimmed = e.target.value.replace(/\s+/g, ''); + onChange(trimmed); + setErrorType(validate(trimmed)); }; const handleSelectItemClick = (selectedValue: string) => { onChange(selectedValue); + setErrorType(false); setOpen(false); }; @@ -66,8 +101,10 @@ const AgeInputWithSelect = ({ value, onChange }: AgeInputWithSelectProps) => { { } }} /> + {errorType === 'format' && ( + + можно только число или диапазон + + )} + {errorType === 'range' && ( + + таких возрастов нет + + )} Date: Tue, 3 Jun 2025 21:10:14 +0300 Subject: [PATCH 23/43] +qid --- src/pages/PersonalizationAI/AuditoryLink.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/PersonalizationAI/AuditoryLink.tsx b/src/pages/PersonalizationAI/AuditoryLink.tsx index a317481c..3d109f4b 100644 --- a/src/pages/PersonalizationAI/AuditoryLink.tsx +++ b/src/pages/PersonalizationAI/AuditoryLink.tsx @@ -1,6 +1,7 @@ import { AuditoryItem } from "@/api/auditory"; import CopyIcon from "@/assets/icons/CopyIcon"; import Trash from "@/assets/icons/trash"; +import { useCurrentQuiz } from "@/stores/quizes/hooks"; import { InfoPopover } from "@/ui_kit/InfoPopover"; import TooltipClickInfo from "@/ui_kit/Toolbars/TooltipClickInfo"; import { useDomainDefine } from "@/utils/hooks/useDomainDefine"; @@ -15,6 +16,7 @@ interface AuditoryLinkProps { export const AuditoryLink = ({ utmParams, item, index, onDelete }: AuditoryLinkProps) => { const theme = useTheme(); + const quiz = useCurrentQuiz(); const { isTestServer } = useDomainDefine(); const handleCopy = (text: string) => { @@ -25,7 +27,7 @@ export const AuditoryLink = ({ utmParams, item, index, onDelete }: AuditoryLinkP onDelete(item.id); }; - const linkText = `${isTestServer ? "https://s.hbpn.link/" : "https://hbpn.link/"}?_paud=${item.id}${utmParams}`; + const linkText = `${isTestServer ? "https://s.hbpn.link/" : "https://hbpn.link/"}${quiz.qid}?_paud=${item.id}${utmParams}`; return ( Date: Tue, 3 Jun 2025 21:50:07 +0300 Subject: [PATCH 24/43] =?UTF-8?q?=D0=B4=D0=B8=D0=B7=D0=B0=D0=B1=D0=BB=20?= =?UTF-8?q?=D0=BA=D0=BD=D0=BE=D0=BF=D0=BA=D0=B8=20=D0=BF=D1=80=D0=B8=20?= =?UTF-8?q?=D0=BD=D0=B5=D0=BA=D0=BE=D1=80=D1=80=D0=B5=D0=BA=D1=82=D0=BD?= =?UTF-8?q?=D1=8B=D1=85=20=D1=83=D1=81=D0=BB=D0=BE=D0=B2=D0=B8=D1=8F=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PersonalizationAI/AgeInputWithSelect.tsx | 19 ++++++++++--------- .../GenderAndAgeSelector.tsx | 9 ++++----- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/pages/PersonalizationAI/AgeInputWithSelect.tsx b/src/pages/PersonalizationAI/AgeInputWithSelect.tsx index f7125098..3703373f 100644 --- a/src/pages/PersonalizationAI/AgeInputWithSelect.tsx +++ b/src/pages/PersonalizationAI/AgeInputWithSelect.tsx @@ -18,9 +18,10 @@ import ArrowDownIcon from "@/assets/icons/ArrowDownIcon"; interface AgeInputWithSelectProps { value: string; onChange: (value: string) => void; + onErrorChange?: (isError: boolean) => void; } -const AgeInputWithSelect = ({ value, onChange }: AgeInputWithSelectProps) => { +const AgeInputWithSelect = ({ value, onChange, onErrorChange }: AgeInputWithSelectProps) => { const theme = useTheme(); const [open, setOpen] = useState(false); const anchorRef = useRef(null); @@ -30,36 +31,36 @@ const AgeInputWithSelect = ({ value, onChange }: AgeInputWithSelectProps) => { const validate = (val: string) => { if (!val) return false; // Число (только положительное) - if (/^\d+$/.test(val)) { + if (/^-?\d+$/.test(val)) { const num = Number(val); if (num < 0 || num > 150) return 'range'; return false; } // Диапазон (только положительные числа) - const rangeMatch = val.match(/^(\d+)-(\d+)$/); + const rangeMatch = val.match(/^(-?\d+)-(-?\d+)$/); if (rangeMatch) { const left = Number(rangeMatch[1]); const right = Number(rangeMatch[2]); if (left < 0 || left > 150 || right < 0 || right > 150 || left > right) return 'range'; return false; } - // Если есть минус не в начале диапазона — это ошибка диапазона - if (/^-?\d+-\d+$/.test(val) || /^\d+-\d+-\d+$/.test(val)) { - return 'range'; - } return 'format'; }; const handleInputChange = (e: React.ChangeEvent) => { const filtered = e.target.value.replace(/[^\d-]/g, ''); onChange(filtered); - setErrorType(false); + const err = validate(filtered); + setErrorType(err); + if (onErrorChange) onErrorChange(!!err); }; const handleInputBlur = (e: React.FocusEvent) => { const trimmed = e.target.value.replace(/\s+/g, ''); onChange(trimmed); - setErrorType(validate(trimmed)); + const err = validate(trimmed); + setErrorType(err); + if (onErrorChange) onErrorChange(!!err); }; const handleSelectItemClick = (selectedValue: string) => { diff --git a/src/pages/PersonalizationAI/GenderAndAgeSelector.tsx b/src/pages/PersonalizationAI/GenderAndAgeSelector.tsx index 8c0e7927..267d9e78 100644 --- a/src/pages/PersonalizationAI/GenderAndAgeSelector.tsx +++ b/src/pages/PersonalizationAI/GenderAndAgeSelector.tsx @@ -19,9 +19,8 @@ export default function GenderAndAgeSelector({ handleAdd }: GenderAndAgeSelector const [selectOpen, setSelectOpen] = useState(false); const quiz = useCurrentQuiz(); const { enqueueSnackbar } = useSnackbar(); - const isMobile = useMediaQuery(theme.breakpoints.down(800)); - - const isFormValid = gender && age; + const isMobile = useMediaQuery(theme.breakpoints.down(845)); + const [ageError, setAgeError] = useState(false); const addItem = async () => { if (!quiz?.backendId) { @@ -172,14 +171,14 @@ export default function GenderAndAgeSelector({ handleAdd }: GenderAndAgeSelector }}>Возраст - + + Уверены, что хотите удалить ссылку? + diff --git a/src/ui_kit/Toolbars/TooltipClickInfo.tsx b/src/ui_kit/Toolbars/TooltipClickInfo.tsx index c8f2f353..c23a629f 100644 --- a/src/ui_kit/Toolbars/TooltipClickInfo.tsx +++ b/src/ui_kit/Toolbars/TooltipClickInfo.tsx @@ -12,6 +12,7 @@ export default function TooltipClickInfo({ title }: { title: string }) { const handleTooltipOpen = () => { setOpen(true); }; + return ( <> @@ -23,14 +24,13 @@ export default function TooltipClickInfo({ title }: { title: string }) { placement="top" onClose={handleTooltipClose} open={open} - disableFocusListener - disableHoverListener - disableTouchListener + title={title} + onMouseEnter={handleTooltipOpen} + onMouseLeave={handleTooltipClose} sx={{ fontSize: "12px", p:"10px" }} - title={title} > From 87d4c9d53d6cf92af1a27e7f513d48b0662e36d5 Mon Sep 17 00:00:00 2001 From: Nastya Date: Sat, 7 Jun 2025 06:24:08 +0300 Subject: [PATCH 28/43] =?UTF-8?q?=D0=BD=D0=B5=20=D0=BA=D0=BE=D0=BF=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2=D1=8B=D1=85=20=D1=81=D1=81=D1=8B=D0=BB=D0=BE?= =?UTF-8?q?=D0=BA=20(=D0=B1=D0=B5=D0=B7=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE?= =?UTF-8?q?=D0=B6=D0=BD=D0=BE=D1=81=D1=82=D0=B8=20=D1=82=D0=B5=D1=81=D1=82?= =?UTF-8?q?=D0=B0=20=D0=BF=D0=BE=D0=BA=D0=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/PersonalizationAI/AuditoryLink.tsx | 38 ++++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/src/pages/PersonalizationAI/AuditoryLink.tsx b/src/pages/PersonalizationAI/AuditoryLink.tsx index 3d109f4b..185a69f7 100644 --- a/src/pages/PersonalizationAI/AuditoryLink.tsx +++ b/src/pages/PersonalizationAI/AuditoryLink.tsx @@ -6,6 +6,7 @@ import { InfoPopover } from "@/ui_kit/InfoPopover"; import TooltipClickInfo from "@/ui_kit/Toolbars/TooltipClickInfo"; import { useDomainDefine } from "@/utils/hooks/useDomainDefine"; import { IconButton, ListItem, Typography, useTheme } from "@mui/material"; +import { useMemo } from "react"; interface AuditoryLinkProps { item: AuditoryItem; @@ -19,7 +20,16 @@ export const AuditoryLink = ({ utmParams, item, index, onDelete }: AuditoryLinkP const quiz = useCurrentQuiz(); const { isTestServer } = useDomainDefine(); + const canCopy = useMemo(() => { + if (!item.created_at) return true; + const now = new Date().getTime(); + const created = new Date(item.created_at).getTime(); + const diffInMinutes = (now - created) / (1000 * 60); + return diffInMinutes >= 5; + }, [item.created_at]); + const handleCopy = (text: string) => { + if (!canCopy) return; navigator.clipboard.writeText(text); }; @@ -27,7 +37,7 @@ export const AuditoryLink = ({ utmParams, item, index, onDelete }: AuditoryLinkP onDelete(item.id); }; - const linkText = `${isTestServer ? "https://s.hbpn.link/" : "https://hbpn.link/"}${quiz.qid}?_paud=${item.id}${utmParams}`; + const linkText = `${isTestServer ? "https://s.hbpn.link/" : "https://hbpn.link/"}${quiz?.qid}?_paud=${item.id}${utmParams}`; return ( handleCopy(linkText)} > - + } > {linkText} From 5ea6d6638a4ba6aa706069fa6776ff17dbc6307d Mon Sep 17 00:00:00 2001 From: Nastya Date: Sun, 8 Jun 2025 10:15:23 +0300 Subject: [PATCH 29/43] =?UTF-8?q?=D0=B2=D1=8B=D0=BD=D0=B5=D1=81=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BE=D1=81=D1=8B=20?= =?UTF-8?q?=D1=82=D0=B0=D1=80=D0=B8=D1=84=D0=BE=D0=B2=20=D0=B8=20=D0=BF?= =?UTF-8?q?=D1=80=D0=B8=D0=B2=D0=B8=D0=BB=D0=B5=D0=B3=D0=B8=D0=B9=20=D0=B2?= =?UTF-8?q?=20=D0=BE=D1=82=D0=B4=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9=20?= =?UTF-8?q?=D1=85=D1=83=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/tariff.ts | 5 +- src/api/tariffs.ts | 9 +++ src/pages/PersonalizationAI/PayModal.tsx | 59 +++++++++++++++ src/pages/Tariffs/Tariffs.tsx | 91 +++++------------------- src/utils/hooks/useDiscounts.ts | 10 +++ src/utils/hooks/useTariffs.ts | 19 +++++ src/utils/hooks/useUser.ts | 7 ++ 7 files changed, 121 insertions(+), 79 deletions(-) create mode 100644 src/api/tariffs.ts create mode 100644 src/pages/PersonalizationAI/PayModal.tsx create mode 100644 src/utils/hooks/useDiscounts.ts create mode 100644 src/utils/hooks/useTariffs.ts create mode 100644 src/utils/hooks/useUser.ts diff --git a/src/api/tariff.ts b/src/api/tariff.ts index a0be6e70..48efae84 100644 --- a/src/api/tariff.ts +++ b/src/api/tariff.ts @@ -1,13 +1,11 @@ import { makeRequest } from "@api/makeRequest"; - import { parseAxiosError } from "@utils/parse-error"; - import type { GetTariffsResponse } from "@frontend/kitui"; const API_URL = `${process.env.REACT_APP_DOMAIN}/strator/tariff`; export const getTariffs = async ( - page: number, + page: number = 1, ): Promise<[GetTariffsResponse | null, string?]> => { try { const tariffs = await makeRequest({ @@ -17,7 +15,6 @@ export const getTariffs = async ( return [tariffs]; } catch (nativeError) { const [error] = parseAxiosError(nativeError); - return [null, `Ошибка при получении списка тарифов. ${error}`]; } }; diff --git a/src/api/tariffs.ts b/src/api/tariffs.ts new file mode 100644 index 00000000..c8f86a9f --- /dev/null +++ b/src/api/tariffs.ts @@ -0,0 +1,9 @@ +import { makeRequest } from '@utils/makeRequest'; +import type { GetTariffsResponse } from '@/model/tariff'; + +export const getTariffs = async (): Promise<[GetTariffsResponse | null, string?]> => { + return makeRequest({ + url: `${process.env.REACT_APP_DOMAIN}/tariffs`, + method: 'GET' + }); +}; \ No newline at end of file diff --git a/src/pages/PersonalizationAI/PayModal.tsx b/src/pages/PersonalizationAI/PayModal.tsx new file mode 100644 index 00000000..5780be81 --- /dev/null +++ b/src/pages/PersonalizationAI/PayModal.tsx @@ -0,0 +1,59 @@ +import { useUserStore } from "@/stores/user"; +import { Box, Button, Modal, Typography } from "@mui/material" + +interface Props { + isOpen: boolean; + openCloseHC: (b: boolean) => void; +} + +export const PayModal = ({ + isOpen, + openCloseHC +}: Props) => { + const privilegesOfUser = useUserStore((state) => state.userAccount?.privileges); + const user = useUserStore((state) => state.customerAccount); //у него есть wallet + + + + + + + + + + + + + return ( + openCloseHC(false)} + aria-labelledby="modal-modal-title" + aria-describedby="modal-modal-description" + > + + Данная услуга предоставляется за 500 рублей/опрос. Готовы оплатить? + + + + + + ) +} \ No newline at end of file diff --git a/src/pages/Tariffs/Tariffs.tsx b/src/pages/Tariffs/Tariffs.tsx index 49b63c1e..005bea37 100644 --- a/src/pages/Tariffs/Tariffs.tsx +++ b/src/pages/Tariffs/Tariffs.tsx @@ -1,10 +1,6 @@ -import { logout } from "@api/auth"; import { activatePromocode } from "@api/promocode"; -import type { Tariff } from "@frontend/kitui"; import { useToken } from "@frontend/kitui"; -import { makeRequest } from "@api/makeRequest"; import ArrowLeft from "@icons/questionsPage/arrowLeft"; -import type { GetTariffsResponse } from "@model/tariff"; import { Box, Button, @@ -12,15 +8,11 @@ import { IconButton, Modal, Paper, - Select, Typography, useMediaQuery, useTheme, - MenuItem, } from "@mui/material"; -import { clearQuizData } from "@root/quizes/store"; -import { cleanAuthTicketData } from "@root/ticket"; -import { clearUserData, useUserStore } from "@root/user"; +import { useUserStore } from "@root/user"; import { LogoutButton } from "@ui_kit/LogoutButton"; import { useDomainDefine } from "@utils/hooks/useDomainDefine"; import { enqueueSnackbar } from "notistack"; @@ -34,16 +26,14 @@ import { createTariffElements } from "./tariffsUtils/createTariffElements"; import { currencyFormatter } from "./tariffsUtils/currencyFormatter"; import { useWallet, setCash } from "@root/cash"; import { handleLogoutClick } from "@utils/HandleLogoutClick"; -import { getDiscounts } from "@api/discounts"; import { cartApi } from "@api/cart"; -import { getUser } from "@api/user"; -import { getTariffs } from "@api/tariff"; -import type { Discount } from "@model/discounts"; import { Other } from "./pages/Other"; import { ModalRequestCreate } from "./ModalRequestCreate"; import { cancelCC, useCC } from "@/stores/cc"; import { NavSelect } from "./NavSelect"; +import { useTariffs } from '@utils/hooks/useTariffs'; +import { useDiscounts } from '@utils/hooks/useDiscounts'; const StepperText: Record = { day: "Тарифы на время", @@ -59,9 +49,11 @@ function TariffPage() { const isMobile = useMediaQuery(theme.breakpoints.down(600)); const userId = useUserStore((state) => state.userId); const navigate = useNavigate(); - const [tariffs, setTariffs] = useState([]); - const [user, setUser] = useState(); - const [discounts, setDiscounts] = useState([]); + const user = useUserStore((state) => state.customerAccount); + const a = useUserStore((state) => state.customerAccount); //c wallet + console.log("________________34563875693785692576_____________USERRRRRRR") + console.log(a) + const { data: discounts } = useDiscounts(userId); const [isRequestCreate, setIsRequestCreate] = useState(false); const [openModal, setOpenModal] = useState({}); const { cashString, cashCop, cashRub } = useWallet(); @@ -70,56 +62,20 @@ function TariffPage() { const [promocodeField, setPromocodeField] = useState(""); const cc = useCC(store => store.cc) - const getTariffsList = async (): Promise => { - const tariffsList: Tariff[] = []; - let page = 2 - const [tariffsResponse, tariffsResponseError] = await getTariffs(page - 1); -console.log(tariffsResponse) - if (tariffsResponseError || !tariffsResponse) { - return tariffsList; - } - tariffsList.push(...tariffsResponse.tariffs); + const { data: tariffs, error: tariffsError, isLoading: tariffsLoading } = useTariffs(); - for (page; page <= tariffsResponse.totalPages; page += 1) { - const [tariffsResult] = await getTariffs(page); - - if (tariffsResult) { - tariffsList.push(...tariffsResult.tariffs); - } - } - - return tariffsList; - }; +console.log("________34563875693785692576_____ TARIFFS") +console.log(tariffs) useEffect(() => { - const get = async () => { - const [user, userError] = await getUser(); - - if (userError) { - return; - } - - const tariffsList = await getTariffsList(); - - if (userId) { - const [discounts] = await getDiscounts(userId); - - if (discounts?.length) { - setDiscounts(discounts); - } - } - - setUser(user); - setTariffs(tariffsList); - + if (a) { let cs = currencyFormatter.format(Number(user.wallet.cash) / 100); let cc = Number(user.wallet.cash); let cr = Number(user.wallet.cash) / 100; setCash(cs, cc, cr); - }; - get(); - }, []); + } + }, [a]); useEffect(() => { if (cc) { @@ -203,32 +159,17 @@ console.log(tariffsResponse) if (error) { enqueueSnackbar(error); - return; } enqueueSnackbar(greetings); - - if (!userId) { - return; - } - - const [discounts, discountsError] = await getDiscounts(userId); - - if (discountsError) { - throw new Error(discountsError); - } - - if (discounts?.length) { - setDiscounts(discounts); - } } const startRequestCreate = () => { setIsRequestCreate(true) } - + if (!a) return null; return ( <> setSelectedItem("hide") }, { diff --git a/src/utils/hooks/useDiscounts.ts b/src/utils/hooks/useDiscounts.ts new file mode 100644 index 00000000..21c71ed9 --- /dev/null +++ b/src/utils/hooks/useDiscounts.ts @@ -0,0 +1,10 @@ +import useSWR from 'swr'; +import { getDiscounts } from '@api/discounts'; +import type { Discount } from '@model/discounts'; + +export const useDiscounts = (userId: string | null) => { + return useSWR( + userId ? `discounts/${userId}` : null, + () => getDiscounts(userId!).then(([data]) => data) + ); +}; \ No newline at end of file diff --git a/src/utils/hooks/useTariffs.ts b/src/utils/hooks/useTariffs.ts new file mode 100644 index 00000000..fd1097d2 --- /dev/null +++ b/src/utils/hooks/useTariffs.ts @@ -0,0 +1,19 @@ +import useSWR from 'swr'; +import { getTariffs } from '@/api/tariff'; +import type { GetTariffsResponse, Tariff } from '@frontend/kitui'; + +export const useTariffs = () => { + const { data, error, isLoading } = useSWR('tariffs', async () => { + const [response] = await getTariffs(); + if (response?.tariffs) { + return response.tariffs; + } + return []; + }); + + return { + data, + error, + isLoading + }; +}; \ No newline at end of file diff --git a/src/utils/hooks/useUser.ts b/src/utils/hooks/useUser.ts new file mode 100644 index 00000000..6e59ab31 --- /dev/null +++ b/src/utils/hooks/useUser.ts @@ -0,0 +1,7 @@ +import useSWR from 'swr'; +import { getUser } from '@api/user'; +import type { User } from '@frontend/kitui'; + +export const useUser = () => { + return useSWR('user', getUser); +}; \ No newline at end of file From 61c0357adc3552b2ebaf04ae8513a06575f2eeab Mon Sep 17 00:00:00 2001 From: Nastya Date: Sun, 8 Jun 2025 20:52:55 +0300 Subject: [PATCH 30/43] =?UTF-8?q?=D0=BF=D0=BE=D0=BA=D1=83=D0=BF=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=BF=D1=80=D0=B8=20=D0=BE=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GenderAndAgeSelector.tsx | 81 ++++----------- src/pages/PersonalizationAI/PayModal.tsx | 55 +++++------ .../PersonalizationAI/PersonalizationAI.tsx | 99 ++++++++++++++++++- 3 files changed, 142 insertions(+), 93 deletions(-) diff --git a/src/pages/PersonalizationAI/GenderAndAgeSelector.tsx b/src/pages/PersonalizationAI/GenderAndAgeSelector.tsx index 504f5091..51caf40e 100644 --- a/src/pages/PersonalizationAI/GenderAndAgeSelector.tsx +++ b/src/pages/PersonalizationAI/GenderAndAgeSelector.tsx @@ -1,69 +1,32 @@ -import { Box, FormControl, FormLabel, RadioGroup, FormControlLabel, Radio, Select, MenuItem, useTheme, Button, useMediaQuery, IconButton } from "@mui/material"; -import { InfoPopover } from '@ui_kit/InfoPopover'; +import { Box, FormControl, FormLabel, RadioGroup, FormControlLabel, Radio, useTheme, Button, useMediaQuery } from "@mui/material"; import CheckboxIcon from "@icons/Checkbox"; -import { useState } from "react"; -import { useCurrentQuiz } from "@/stores/quizes/hooks"; -import { auditoryAdd } from "@/api/auditory"; -import { useSnackbar } from "notistack"; -import ArrowDownIcon from "@/assets/icons/ArrowDownIcon"; import AgeInputWithSelect from "./AgeInputWithSelect"; interface GenderAndAgeSelectorProps { - handleAdd: (item: any) => void; + gender: string; + age: string; + ageError: boolean; + onGenderChange: (gender: string) => void; + onAgeChange: (age: string) => void; + onAgeErrorChange: (error: boolean) => void; + onStartCreate: () => void; } -export default function GenderAndAgeSelector({ handleAdd }: GenderAndAgeSelectorProps) { +export default function GenderAndAgeSelector({ + gender, + age, + ageError, + onGenderChange, + onAgeChange, + onAgeErrorChange, + onStartCreate +}: GenderAndAgeSelectorProps) { const theme = useTheme(); - const [age, setAge] = useState(''); - const [gender, setGender] = useState(''); - const [selectOpen, setSelectOpen] = useState(false); - const quiz = useCurrentQuiz(); - const { enqueueSnackbar } = useSnackbar(); const isMobile = useMediaQuery(theme.breakpoints.down(845)); - const [ageError, setAgeError] = useState(false); - - const addItem = async () => { - if (!quiz?.backendId) { - enqueueSnackbar('Ошибка: не выбран квиз', { variant: 'error' }); - return; - } - - try { - const [result, error] = await auditoryAdd({ - quizId: quiz.backendId, - body: { - sex: gender === "male", - age - } - }); - - if (error) { - enqueueSnackbar('Не удалось добавить ссылку', { variant: 'error' }); - return; - } - - if (result) { - handleAdd({ - id: result.ID, - quiz_id: quiz.backendId, - sex: gender === "male", - age, - deleted: false, - }); - enqueueSnackbar('Ссылка успешно добавлена', { variant: 'success' }); - // Очищаем форму - setGender(''); - setAge(''); - } - } catch (error) { - enqueueSnackbar('Произошла ошибка при добавлении', { variant: 'error' }); - } - }; return ( - Пол - {/* */} setGender(e.target.value)} + onChange={(e) => onGenderChange(e.target.value)} > Возраст - {/* */} - + - + ); } \ No newline at end of file diff --git a/src/pages/PersonalizationAI/PayModal.tsx b/src/pages/PersonalizationAI/PayModal.tsx index 5780be81..2e51c828 100644 --- a/src/pages/PersonalizationAI/PayModal.tsx +++ b/src/pages/PersonalizationAI/PayModal.tsx @@ -1,33 +1,21 @@ -import { useUserStore } from "@/stores/user"; import { Box, Button, Modal, Typography } from "@mui/material" interface Props { - isOpen: boolean; - openCloseHC: (b: boolean) => void; + open: boolean; + onClose: () => void; + onCreate: () => void; } + export const PayModal = ({ - isOpen, - openCloseHC + open, + onClose, + onCreate }: Props) => { - const privilegesOfUser = useUserStore((state) => state.userAccount?.privileges); - const user = useUserStore((state) => state.customerAccount); //у него есть wallet - - - - - - - - - - - - return ( openCloseHC(false)} + open={open} + onClose={onClose} aria-labelledby="modal-modal-title" aria-describedby="modal-modal-description" > @@ -37,23 +25,30 @@ export const PayModal = ({ top: "50%", left: "50%", transform: "translate(-50%, -50%)", - maxWidth: "620px", + maxWidth: "550px", width: "100%", bgcolor: "background.paper", borderRadius: "12px", - boxShadow: 24, - p: "20px", + p: "30px", display: "flex", flexDirection: "column", - alignItems: "center" + alignItems: "center", + gap: 2 }} > - Данная услуга предоставляется за 500 рублей/опрос. Готовы оплатить? - - + + Данная услуга предоставляется за 500 рублей/опрос. Готовы оплатить? + + + + + - - ) + ); } \ No newline at end of file diff --git a/src/pages/PersonalizationAI/PersonalizationAI.tsx b/src/pages/PersonalizationAI/PersonalizationAI.tsx index e2e4f7e4..cedd211c 100644 --- a/src/pages/PersonalizationAI/PersonalizationAI.tsx +++ b/src/pages/PersonalizationAI/PersonalizationAI.tsx @@ -8,8 +8,11 @@ import { AuditoryItem, auditoryAdd, auditoryDelete, auditoryGet } from "@/api/au import { useCurrentQuiz } from "@/stores/quizes/hooks"; import { AuditoryList } from "./AuditoryList"; import { useSnackbar } from "notistack"; +import { PayModal } from "./PayModal"; +import { useUserStore } from "@/stores/user"; +import { cartApi } from "@/api/cart"; - +const tariff = "6844b8858258f5cc35791ef7"; export default function PersonalizationAI() { const theme = useTheme(); const [auditory, setAuditory] = useState([]); @@ -18,6 +21,70 @@ export default function PersonalizationAI() { const [utmParams, setUtmParams] = useState(''); const quiz = useCurrentQuiz(); const { enqueueSnackbar } = useSnackbar(); + const privilegesOfUser = useUserStore((state) => state.userAccount?.privileges); + + const [isStartCreate, setStartCreate] = useState(false); + const [gender, setGender] = useState(''); + const [age, setAge] = useState(''); + const [ageError, setAgeError] = useState(false); + const [isModalOpen, setIsModalOpen] = useState(false); + + const resetForm = () => { + setGender(''); + setAge(''); + setAgeError(false); + }; + + const checkPrivileges = async () => { + // TODO: Здесь будет проверка прав пользователя + console.log("______________privilegesOfUser"); + console.log(privilegesOfUser); + const [_, addError] = await cartApi.add(tariff); + + if (addError) return; + + + //Если нам хватает денежек - покупаем тариф + const [data, payError] = await cartApi.pay(); + }; + + const createNewLink = async () => { + if (!quiz?.backendId) { + enqueueSnackbar('Ошибка: не выбран квиз', { variant: 'error' }); + return; + } + + try { + const [result, error] = await auditoryAdd({ + quizId: quiz.backendId, + body: { + sex: gender === "male", + age + } + }); + + if (error) { + enqueueSnackbar('Не удалось добавить ссылку', { variant: 'error' }); + return; + } + + if (result) { + handleAdd({ + id: result.ID, + quiz_id: quiz.backendId, + sex: gender === "male", + age, + deleted: false, + }); + enqueueSnackbar('Ссылка успешно добавлена', { variant: 'success' }); + resetForm(); + setIsModalOpen(false); + setStartCreate(false); + } + } catch (error) { + enqueueSnackbar('Произошла ошибка при добавлении', { variant: 'error' }); + } + }; useEffect(() => { (async () => { @@ -74,7 +141,10 @@ export default function PersonalizationAI() { } const handleAdd = (item: AuditoryItem) => { - setAuditory(old => ([...old, item])) + setAuditory(old => ([...old, item])); + // Очищаем форму после успешного добавления + setGender(''); + setAge(''); } const handleLinkChange = (e: React.ChangeEvent) => { @@ -101,6 +171,13 @@ export default function PersonalizationAI() { setUtmParams(paramString ? `&${paramString}` : ""); }; + const startCreate = () => { + setStartCreate(true); + if (checkPrivileges()) { + setIsModalOpen(true); + } + }; + return ( <> @@ -124,7 +201,15 @@ export default function PersonalizationAI() { boxShadow: "none", maxWidth: "796px" }}> - + {/* Ссылка */} @@ -188,6 +273,14 @@ export default function PersonalizationAI() { + { + setIsModalOpen(false); + setStartCreate(false); + }} + onCreate={createNewLink} + /> ); } From 918b6bf145560067a2b99a7e590574e0f3871172 Mon Sep 17 00:00:00 2001 From: Nastya Date: Sun, 8 Jun 2025 22:56:22 +0300 Subject: [PATCH 31/43] =?UTF-8?q?=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6?= =?UTF-8?q?=D0=BD=D0=BE=D1=81=D1=82=D1=8C=20=D0=B2=D1=8B=D0=B1=D1=80=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20=D0=B8=20=D0=BA=D0=BE=D1=80=D1=80=D0=B5=D0=BA?= =?UTF-8?q?=D1=82=D0=BD=D0=BE=20=D0=BE=D1=82=D0=BF=D1=80=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BF=D0=BE=D0=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/auditory.ts | 11 +++- src/pages/PersonalizationAI/AuditoryLink.tsx | 2 +- .../GenderAndAgeSelector.tsx | 63 +++++++++++++++---- .../PersonalizationAI/PersonalizationAI.tsx | 7 ++- 4 files changed, 64 insertions(+), 19 deletions(-) diff --git a/src/api/auditory.ts b/src/api/auditory.ts index f0ca4914..dfa814aa 100644 --- a/src/api/auditory.ts +++ b/src/api/auditory.ts @@ -7,14 +7,19 @@ const API_URL = `${process.env.REACT_APP_DOMAIN}/squiz`; export interface AuditoryItem { id: number; quiz_id: number; - sex: boolean; + sex: number; // 0 - женский, 1 - мужской, 2 - оба age: string; deleted: boolean; created_at: number; } export interface AuditoryResponse { - data: AuditoryItem[]; + ID: number; + quiz_id: number; + sex: number; + age: string; + deleted: boolean; + created_at: number; } // Request Types @@ -27,7 +32,7 @@ export interface AuditoryDeleteRequest { } export interface AuditoryAddRequest { - sex: boolean; + sex: number; age: string; } diff --git a/src/pages/PersonalizationAI/AuditoryLink.tsx b/src/pages/PersonalizationAI/AuditoryLink.tsx index 185a69f7..8a15cf49 100644 --- a/src/pages/PersonalizationAI/AuditoryLink.tsx +++ b/src/pages/PersonalizationAI/AuditoryLink.tsx @@ -75,7 +75,7 @@ export const AuditoryLink = ({ utmParams, item, index, onDelete }: AuditoryLinkP }} /> - + { + if (type === 'male') { + setMaleChecked(checked); + } else { + setFemaleChecked(checked); + } + + // Обновляем значение gender в родительском компоненте + if (type === 'male' && checked && !femaleChecked) { + onGenderChange('1'); // Только мужской + } else if (type === 'female' && checked && !maleChecked) { + onGenderChange('0'); // Только женский + } else if (type === 'male' && checked && femaleChecked) { + onGenderChange('2'); // Оба пола + } else if (type === 'female' && checked && maleChecked) { + onGenderChange('2'); // Оба пола + } else if (type === 'male' && !checked && femaleChecked) { + onGenderChange('0'); // Только женский + } else if (type === 'female' && !checked && maleChecked) { + onGenderChange('1'); // Только мужской + } else { + onGenderChange(''); // Ничего не выбрано + } + }; return ( @@ -43,18 +71,15 @@ export default function GenderAndAgeSelector({ }} component="legend">Пол - onGenderChange(e.target.value)} > } checkedIcon={} />} + control={ + } + checkedIcon={} + checked={maleChecked} + onChange={(e) => handleGenderChange('male', e.target.checked)} + /> + } label="М" /> } checkedIcon={} />} + control={ + } + checkedIcon={} + checked={femaleChecked} + onChange={(e) => handleGenderChange('female', e.target.checked)} + /> + } label="Ж" /> - + diff --git a/src/pages/PersonalizationAI/PersonalizationAI.tsx b/src/pages/PersonalizationAI/PersonalizationAI.tsx index cedd211c..68991080 100644 --- a/src/pages/PersonalizationAI/PersonalizationAI.tsx +++ b/src/pages/PersonalizationAI/PersonalizationAI.tsx @@ -25,6 +25,8 @@ export default function PersonalizationAI() { const [isStartCreate, setStartCreate] = useState(false); const [gender, setGender] = useState(''); + console.log("gender") + console.log(gender) const [age, setAge] = useState(''); const [ageError, setAgeError] = useState(false); const [isModalOpen, setIsModalOpen] = useState(false); @@ -58,7 +60,7 @@ export default function PersonalizationAI() { const [result, error] = await auditoryAdd({ quizId: quiz.backendId, body: { - sex: gender === "male", + sex: parseInt(gender), age } }); @@ -72,9 +74,10 @@ export default function PersonalizationAI() { handleAdd({ id: result.ID, quiz_id: quiz.backendId, - sex: gender === "male", + sex: parseInt(gender), age, deleted: false, + created_at: Date.now() }); enqueueSnackbar('Ссылка успешно добавлена', { variant: 'success' }); resetForm(); From eb5f8168c86ca54d5e458d7533e0036c0c00a66f Mon Sep 17 00:00:00 2001 From: Nastya Date: Sun, 8 Jun 2025 23:08:47 +0300 Subject: [PATCH 32/43] =?UTF-8?q?=D0=BE=D1=81=D1=82=D0=B0=D0=BB=D0=BE?= =?UTF-8?q?=D1=81=D1=8C=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D1=82=D1=8C?= =?UTF-8?q?=20=D0=BF=D0=BE=D0=BF=D0=BE=D0=BB=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5?= =?UTF-8?q?=20=D1=81=D1=87=D1=91=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PersonalizationAI/PersonalizationAI.tsx | 45 +++++++++++++------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/src/pages/PersonalizationAI/PersonalizationAI.tsx b/src/pages/PersonalizationAI/PersonalizationAI.tsx index 68991080..5e3c8c3b 100644 --- a/src/pages/PersonalizationAI/PersonalizationAI.tsx +++ b/src/pages/PersonalizationAI/PersonalizationAI.tsx @@ -38,16 +38,9 @@ export default function PersonalizationAI() { }; const checkPrivileges = async () => { - // TODO: Здесь будет проверка прав пользователя - console.log("______________privilegesOfUser"); - console.log(privilegesOfUser); - const [_, addError] = await cartApi.add(tariff); - - if (addError) return; - - - //Если нам хватает денежек - покупаем тариф - const [data, payError] = await cartApi.pay(); + if (privilegesOfUser?.quizGigaChat && privilegesOfUser.quizGigaChat.amount > 0) { + return true; + } else return false; }; const createNewLink = async () => { @@ -174,13 +167,37 @@ export default function PersonalizationAI() { setUtmParams(paramString ? `&${paramString}` : ""); }; - const startCreate = () => { + const startCreate = async () => { setStartCreate(true); - if (checkPrivileges()) { + const hasPrivileges = await checkPrivileges(); + if (hasPrivileges) { + createNewLink(); + } else { setIsModalOpen(true); } }; + const tryBuy = () => { + alert("старт покупки") + /* + // Добавляем тариф в корзину + const [_, addError] = await cartApi.add(tariff); + if (addError) { + enqueueSnackbar('Не удалось добавить тариф в корзину', { variant: 'error' }); + return false; + } + + // Пытаемся оплатить + const [data, payError] = await cartApi.pay(); + if (payError) { + enqueueSnackbar('Не удалось оплатить тариф', { variant: 'error' }); + return false; + } + + return true; + */ + } + return ( <> @@ -204,7 +221,7 @@ export default function PersonalizationAI() { boxShadow: "none", maxWidth: "796px" }}> - ); From ac7c0017388d179dbc9b68fbcc3786733109727f Mon Sep 17 00:00:00 2001 From: Nastya Date: Sun, 8 Jun 2025 23:23:24 +0300 Subject: [PATCH 33/43] =?UTF-8?q?=D0=BE=D0=BF=D0=BB=D0=B0=D1=82=D0=B0=20?= =?UTF-8?q?=D1=87=D0=B5=D1=80=D0=B5=D0=B7=20=D1=85=D0=B0=D0=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PersonalizationAI/PersonalizationAI.tsx | 64 +++++++++++++------ src/pages/Tariffs/Tariffs.tsx | 2 +- 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/src/pages/PersonalizationAI/PersonalizationAI.tsx b/src/pages/PersonalizationAI/PersonalizationAI.tsx index 5e3c8c3b..bc8b2dc4 100644 --- a/src/pages/PersonalizationAI/PersonalizationAI.tsx +++ b/src/pages/PersonalizationAI/PersonalizationAI.tsx @@ -11,6 +11,10 @@ import { useSnackbar } from "notistack"; import { PayModal } from "./PayModal"; import { useUserStore } from "@/stores/user"; import { cartApi } from "@/api/cart"; +import { outCart } from "../Tariffs/Tariffs"; +import { inCart } from "../Tariffs/Tariffs"; +import { isTestServer } from "@/utils/hooks/useDomainDefine"; +import { useToken } from "@frontend/kitui"; const tariff = "6844b8858258f5cc35791ef7"; export default function PersonalizationAI() { @@ -22,6 +26,9 @@ export default function PersonalizationAI() { const quiz = useCurrentQuiz(); const { enqueueSnackbar } = useSnackbar(); const privilegesOfUser = useUserStore((state) => state.userAccount?.privileges); + const user = useUserStore((state) => state.customerAccount); + const token = useToken(); + const userId = useUserStore((state) => state.userId); const [isStartCreate, setStartCreate] = useState(false); const [gender, setGender] = useState(''); @@ -177,26 +184,43 @@ export default function PersonalizationAI() { } }; - const tryBuy = () => { - alert("старт покупки") - /* - // Добавляем тариф в корзину - const [_, addError] = await cartApi.add(tariff); - if (addError) { - enqueueSnackbar('Не удалось добавить тариф в корзину', { variant: 'error' }); - return false; - } - - // Пытаемся оплатить - const [data, payError] = await cartApi.pay(); - if (payError) { - enqueueSnackbar('Не удалось оплатить тариф', { variant: 'error' }); - return false; - } - - return true; - */ - } + const tryBuy = async ({ id, price }: { id: string; price: number }) => { + //Если в корзине что-то было - выкладываем содержимое и запоминаем чо там лежало + if (user.cart.length > 0) { + outCart(user.cart); + } + //Добавляем желаемый тариф в корзину + const [_, addError] = await cartApi.add(tariff); + + if (addError) { + //Развращаем товары в корзину + inCart(); + + return; + } + + //Если нам хватает денежек - покупаем тариф + const [data, payError] = await cartApi.pay(); + + if (payError || !data) { + //если денег не хватило + if (payError?.includes("insufficient funds") || payError?.includes("Payment Required")) { + var link = document.createElement("a"); + link.href = `https://${isTestServer ? "s" : ""}hub.pena.digital/quizpayment?action=squizpay&dif=50000&data=${token}&userid=${userId}&from=AI`; + document.body.appendChild(link); + link.click(); + return; + } + + //другая ошибка + enqueueSnackbar("Произошла ошибка. Попробуйте позже"); + + return; + } + + //Развращаем товары в корзину + inCart(); + }; return ( <> diff --git a/src/pages/Tariffs/Tariffs.tsx b/src/pages/Tariffs/Tariffs.tsx index 005bea37..5a886bb0 100644 --- a/src/pages/Tariffs/Tariffs.tsx +++ b/src/pages/Tariffs/Tariffs.tsx @@ -387,7 +387,7 @@ export const inCart = () => { localStorage.setItem("saveCart", "[]"); } }; -const outCart = (cart: string[]) => { +export const outCart = (cart: string[]) => { //Сделаем муторно и подольше, зато при прерывании сессии данные потеряются минимально if (cart.length > 0) { cart.forEach(async (id: string) => { From 9bb69f1ab240ed1ee1fb55e4a96f38db6c9c1b69 Mon Sep 17 00:00:00 2001 From: Nastya Date: Mon, 9 Jun 2025 16:16:55 +0300 Subject: [PATCH 34/43] =?UTF-8?q?=D0=BE=D0=B1=D0=BD=D0=BE=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20?= =?UTF-8?q?=D0=BE=20=D1=8E=D0=B7=D0=B5=D1=80=D0=B5=20=D0=BF=D0=BE=D1=81?= =?UTF-8?q?=D0=BB=D0=B5=20=D0=BF=D0=BE=D0=BA=D1=83=D0=BF=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PersonalizationAI/PersonalizationAI.tsx | 67 ++++++++++++++----- src/utils/hooks/useUser.ts | 2 +- src/utils/hooks/useUserAccountFetcher.ts | 4 +- 3 files changed, 53 insertions(+), 20 deletions(-) diff --git a/src/pages/PersonalizationAI/PersonalizationAI.tsx b/src/pages/PersonalizationAI/PersonalizationAI.tsx index bc8b2dc4..e57e5c69 100644 --- a/src/pages/PersonalizationAI/PersonalizationAI.tsx +++ b/src/pages/PersonalizationAI/PersonalizationAI.tsx @@ -15,6 +15,9 @@ import { outCart } from "../Tariffs/Tariffs"; import { inCart } from "../Tariffs/Tariffs"; import { isTestServer } from "@/utils/hooks/useDomainDefine"; import { useToken } from "@frontend/kitui"; +import { useSWRConfig } from "swr"; +import { makeRequest } from "@api/makeRequest"; +import { setUserAccount, setCustomerAccount } from "@/stores/user"; const tariff = "6844b8858258f5cc35791ef7"; export default function PersonalizationAI() { @@ -30,13 +33,12 @@ export default function PersonalizationAI() { const token = useToken(); const userId = useUserStore((state) => state.userId); - const [isStartCreate, setStartCreate] = useState(false); const [gender, setGender] = useState(''); - console.log("gender") - console.log(gender) const [age, setAge] = useState(''); const [ageError, setAgeError] = useState(false); const [isModalOpen, setIsModalOpen] = useState(false); + // Обновляем данные пользователя через SWR + const { mutate } = useSWRConfig(); const resetForm = () => { setGender(''); @@ -44,11 +46,6 @@ export default function PersonalizationAI() { setAgeError(false); }; - const checkPrivileges = async () => { - if (privilegesOfUser?.quizGigaChat && privilegesOfUser.quizGigaChat.amount > 0) { - return true; - } else return false; - }; const createNewLink = async () => { if (!quiz?.backendId) { @@ -67,7 +64,7 @@ export default function PersonalizationAI() { if (error) { enqueueSnackbar('Не удалось добавить ссылку', { variant: 'error' }); - return; + return [, error]; } if (result) { @@ -82,7 +79,42 @@ export default function PersonalizationAI() { enqueueSnackbar('Ссылка успешно добавлена', { variant: 'success' }); resetForm(); setIsModalOpen(false); - setStartCreate(false); + + // Обновляем данные пользователя после успешного создания ссылки + try { + const [userAccountResult, customerAccountResult] = await Promise.all([ + makeRequest({ + url: `${process.env.REACT_APP_DOMAIN}/squiz/account/get`, + method: "GET", + useToken: true, + withCredentials: false, + }).catch(error => { + console.log(error) + enqueueSnackbar("Ошибка при обновлении данных пользователя", { variant: "error" }); + return null; + }), + makeRequest({ + url: `${process.env.REACT_APP_DOMAIN}/customer/v1.0.1/account`, + method: "GET", + useToken: true, + withCredentials: false, + }).catch(error => { + console.log(error) + enqueueSnackbar("Ошибка при обновлении данных клиента", { variant: "error" }); + return null; + }) + ]); + + if (userAccountResult) { + setUserAccount(userAccountResult); + } + if (customerAccountResult) { + setCustomerAccount(customerAccountResult); + } + } catch (error) { + console.log(error) + enqueueSnackbar("Ошибка при обновлении данных", { variant: "error" }); + } } } catch (error) { enqueueSnackbar('Произошла ошибка при добавлении', { variant: 'error' }); @@ -174,10 +206,10 @@ export default function PersonalizationAI() { setUtmParams(paramString ? `&${paramString}` : ""); }; + console.log("______-------__________---------_____---__--__-__--___------__--_---_--_----__--__-__--_--__--__--_---_______-privilegesOfUser") + console.log(privilegesOfUser) const startCreate = async () => { - setStartCreate(true); - const hasPrivileges = await checkPrivileges(); - if (hasPrivileges) { + if (privilegesOfUser?.quizGigaChat && privilegesOfUser.quizGigaChat.amount > 0) { createNewLink(); } else { setIsModalOpen(true); @@ -186,7 +218,7 @@ export default function PersonalizationAI() { const tryBuy = async ({ id, price }: { id: string; price: number }) => { //Если в корзине что-то было - выкладываем содержимое и запоминаем чо там лежало - if (user.cart.length > 0) { + if (user?.cart?.length > 0) { outCart(user.cart); } //Добавляем желаемый тариф в корзину @@ -195,7 +227,6 @@ export default function PersonalizationAI() { if (addError) { //Развращаем товары в корзину inCart(); - return; } @@ -214,12 +245,15 @@ export default function PersonalizationAI() { //другая ошибка enqueueSnackbar("Произошла ошибка. Попробуйте позже"); - return; } //Развращаем товары в корзину inCart(); + + + // Если покупка прошла успешно, создаем новую ссылку + createNewLink(); }; return ( @@ -321,7 +355,6 @@ export default function PersonalizationAI() { open={isModalOpen} onClose={() => { setIsModalOpen(false); - setStartCreate(false); }} onCreate={tryBuy} /> diff --git a/src/utils/hooks/useUser.ts b/src/utils/hooks/useUser.ts index 6e59ab31..3d734315 100644 --- a/src/utils/hooks/useUser.ts +++ b/src/utils/hooks/useUser.ts @@ -1,7 +1,7 @@ import useSWR from 'swr'; import { getUser } from '@api/user'; import type { User } from '@frontend/kitui'; - + export const useUser = () => { return useSWR('user', getUser); }; \ No newline at end of file diff --git a/src/utils/hooks/useUserAccountFetcher.ts b/src/utils/hooks/useUserAccountFetcher.ts index add6d374..f057114f 100644 --- a/src/utils/hooks/useUserAccountFetcher.ts +++ b/src/utils/hooks/useUserAccountFetcher.ts @@ -1,9 +1,7 @@ import { useEffect, useLayoutEffect, useRef } from "react"; import { createUserAccount, devlog } from "@frontend/kitui"; import { isAxiosError } from "axios"; - import { makeRequest } from "@api/makeRequest"; - import type { UserAccount } from "@frontend/kitui"; import { setUserAccount } from "@/stores/user"; @@ -20,10 +18,12 @@ export const useUserAccountFetcher = ({ }) => { const onNewUserAccountRef = useRef(onNewUserAccount); const onErrorRef = useRef(onError); + useLayoutEffect(() => { onNewUserAccountRef.current = onNewUserAccount; onErrorRef.current = onError; }, [onError, onNewUserAccount]); + useEffect(() => { if (!userId) return; const controller = new AbortController(); From 6465652f82b76d625f19e7998b36f590e5546b31 Mon Sep 17 00:00:00 2001 From: Nastya Date: Mon, 9 Jun 2025 17:26:19 +0300 Subject: [PATCH 35/43] =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D0=B2=D0=BE?= =?UTF-8?q?=D0=B4=20=D0=BD=D0=B0=20=D0=B0=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/PersonalizationAI/PersonalizationAI.tsx | 2 +- src/utils/hooks/useAutoPay.ts | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/pages/PersonalizationAI/PersonalizationAI.tsx b/src/pages/PersonalizationAI/PersonalizationAI.tsx index e57e5c69..bb2bf0d9 100644 --- a/src/pages/PersonalizationAI/PersonalizationAI.tsx +++ b/src/pages/PersonalizationAI/PersonalizationAI.tsx @@ -237,7 +237,7 @@ export default function PersonalizationAI() { //если денег не хватило if (payError?.includes("insufficient funds") || payError?.includes("Payment Required")) { var link = document.createElement("a"); - link.href = `https://${isTestServer ? "s" : ""}hub.pena.digital/quizpayment?action=squizpay&dif=50000&data=${token}&userid=${userId}&from=AI`; + link.href = `https://${isTestServer ? "s" : ""}hub.pena.digital/quizpayment?action=squizpay&dif=50000&data=${token}&userid=${userId}&from=AI&wayback=ai_${quiz?.backendId}`; document.body.appendChild(link); link.click(); return; diff --git a/src/utils/hooks/useAutoPay.ts b/src/utils/hooks/useAutoPay.ts index d0591061..530c2378 100644 --- a/src/utils/hooks/useAutoPay.ts +++ b/src/utils/hooks/useAutoPay.ts @@ -6,6 +6,7 @@ import { useEffect } from "react"; import { redirect, useNavigate, useSearchParams } from "react-router-dom"; import { calcTimeOfReadyPayCart, cancelPayCartProcess, startPayCartProcess, useNotEnoughMoneyAmount } from "@/stores/notEnoughMoneyAmount"; import { startCC } from "@/stores/cc"; +import { setEditQuizId, setCurrentStep } from "@root/quizes/actions"; export const useAfterPay = () => { const navigate = useNavigate(); @@ -17,7 +18,19 @@ export const useAfterPay = () => { const purpose = searchParams.get("purpose"); const paymentUserId = searchParams.get("userid"); const currentCC = searchParams.get("cc"); + const wayback = searchParams.get("wayback"); + // Обработка wayback параметра + useEffect(() => { + if (wayback) { + const quizId = wayback.split("_")[1]; + if (quizId) { + setEditQuizId(Number(quizId)); + setCurrentStep(17); // Шаг для персонализации AI + navigate("/edit"); + } + } + }, [wayback, navigate]); useEffect(() => { //Звёзды сошлись, будем оплачивать корзину @@ -25,7 +38,7 @@ export const useAfterPay = () => { if (purpose === "paycart") { setSearchParams({}, { replace: true }); - if (currentCC) { startCC() } + if (currentCC) startCC() (async () => { //Проверяем можем ли мы оплатить корзину здесь и сейчас From 929e6047cff04786118545edaf2ebcf06f5ee534 Mon Sep 17 00:00:00 2001 From: Nastya Date: Mon, 9 Jun 2025 18:22:41 +0300 Subject: [PATCH 36/43] fix checkbox --- .../GenderAndAgeSelector.tsx | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/pages/PersonalizationAI/GenderAndAgeSelector.tsx b/src/pages/PersonalizationAI/GenderAndAgeSelector.tsx index 8fa20586..720022f3 100644 --- a/src/pages/PersonalizationAI/GenderAndAgeSelector.tsx +++ b/src/pages/PersonalizationAI/GenderAndAgeSelector.tsx @@ -1,7 +1,7 @@ import { Box, FormControl, FormLabel, Checkbox, FormControlLabel, useTheme, Button, useMediaQuery } from "@mui/material"; import CheckboxIcon from "@icons/Checkbox"; import AgeInputWithSelect from "./AgeInputWithSelect"; -import { useState } from "react"; +import { useState, useEffect } from "react"; interface GenderAndAgeSelectorProps { gender: string; @@ -27,6 +27,23 @@ export default function GenderAndAgeSelector({ const [maleChecked, setMaleChecked] = useState(false); const [femaleChecked, setFemaleChecked] = useState(false); + // Синхронизируем состояние чекбоксов с пропсом gender + useEffect(() => { + if (gender === '1') { + setMaleChecked(true); + setFemaleChecked(false); + } else if (gender === '0') { + setMaleChecked(false); + setFemaleChecked(true); + } else if (gender === '2') { + setMaleChecked(true); + setFemaleChecked(true); + } else { + setMaleChecked(false); + setFemaleChecked(false); + } + }, [gender]); + const handleGenderChange = (type: 'male' | 'female', checked: boolean) => { if (type === 'male') { setMaleChecked(checked); From c396752ce68a4c22ccc2a3b72bf99d3a58d54878 Mon Sep 17 00:00:00 2001 From: Nastya Date: Mon, 9 Jun 2025 23:55:24 +0300 Subject: [PATCH 37/43] -- --- src/pages/ResultPage/ResultPage.tsx | 1 + src/utils/hooks/useAutoPay.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/ResultPage/ResultPage.tsx b/src/pages/ResultPage/ResultPage.tsx index c49ef5e3..a70dcb38 100644 --- a/src/pages/ResultPage/ResultPage.tsx +++ b/src/pages/ResultPage/ResultPage.tsx @@ -3,6 +3,7 @@ import { ResultSettings } from "./ResultSettings"; import { decrementCurrentStep, incrementCurrentStep, + setCurrentStep, } from "@root/quizes/actions"; import { Box, Button } from "@mui/material"; import ArrowLeft from "@icons/questionsPage/arrowLeft"; diff --git a/src/utils/hooks/useAutoPay.ts b/src/utils/hooks/useAutoPay.ts index 530c2378..cc46fde5 100644 --- a/src/utils/hooks/useAutoPay.ts +++ b/src/utils/hooks/useAutoPay.ts @@ -27,7 +27,7 @@ export const useAfterPay = () => { if (quizId) { setEditQuizId(Number(quizId)); setCurrentStep(17); // Шаг для персонализации AI - navigate("/edit"); + navigate("/personalization-ai"); } } }, [wayback, navigate]); From a8d6db9f2df16893f2ffae26b9375ae738aa5657 Mon Sep 17 00:00:00 2001 From: Nastya Date: Tue, 10 Jun 2025 23:04:01 +0300 Subject: [PATCH 38/43] =?UTF-8?q?=D1=80=D0=B5=D0=B0=D0=BA=D1=82=D0=B8?= =?UTF-8?q?=D0=B2=D0=BD=D0=BE=D0=B5=20=D0=BE=D1=82=D0=BE=D0=B1=D1=80=D0=B0?= =?UTF-8?q?=D0=B6=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=81=D0=BA=D0=B5=D0=BB=D0=B5?= =?UTF-8?q?=D1=82=D0=BE=D0=BD=D0=BE=D0=B2=20=D0=B2=D0=BC=D0=B5=D1=81=D1=82?= =?UTF-8?q?=D0=BE=20=D0=BA=D0=BE=D0=BF=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/PersonalizationAI/AuditoryLink.tsx | 105 +++++++++++++++---- 1 file changed, 83 insertions(+), 22 deletions(-) diff --git a/src/pages/PersonalizationAI/AuditoryLink.tsx b/src/pages/PersonalizationAI/AuditoryLink.tsx index 8a15cf49..0e17653f 100644 --- a/src/pages/PersonalizationAI/AuditoryLink.tsx +++ b/src/pages/PersonalizationAI/AuditoryLink.tsx @@ -5,8 +5,8 @@ import { useCurrentQuiz } from "@/stores/quizes/hooks"; import { InfoPopover } from "@/ui_kit/InfoPopover"; import TooltipClickInfo from "@/ui_kit/Toolbars/TooltipClickInfo"; import { useDomainDefine } from "@/utils/hooks/useDomainDefine"; -import { IconButton, ListItem, Typography, useTheme } from "@mui/material"; -import { useMemo } from "react"; +import { IconButton, ListItem, Skeleton, Typography, useTheme } from "@mui/material"; +import { useEffect, useMemo, useState } from "react"; interface AuditoryLinkProps { item: AuditoryItem; @@ -20,16 +20,66 @@ export const AuditoryLink = ({ utmParams, item, index, onDelete }: AuditoryLinkP const quiz = useCurrentQuiz(); const { isTestServer } = useDomainDefine(); - const canCopy = useMemo(() => { - if (!item.created_at) return true; + const getCreatedTime = (timestamp: number) => { + // Если timestamp в секундах (10 цифр) + if (timestamp.toString().length === 10) { + return new Date(timestamp * 1000).getTime(); + } + // Если timestamp в миллисекундах (13 цифр) + return new Date(timestamp).getTime(); + }; + + const [isLoading, setIsLoading] = useState(() => { + if (!item.created_at) return false; const now = new Date().getTime(); - const created = new Date(item.created_at).getTime(); + const created = getCreatedTime(item.created_at); const diffInMinutes = (now - created) / (1000 * 60); - return diffInMinutes >= 5; + console.log('Initial state:', { + created_at: item.created_at, + format: item.created_at.toString().length === 10 ? 'seconds' : 'milliseconds', + now, + created, + diffInMinutes, + isLoading: diffInMinutes < 2 + }); + return diffInMinutes < 2; + }); + + useEffect(() => { + if (!item.created_at) return; + + const now = new Date().getTime(); + const created = getCreatedTime(item.created_at); + const diffInMinutes = (now - created) / (1000 * 60); + + console.log('Effect check:', { + created_at: item.created_at, + format: item.created_at.toString().length === 10 ? 'seconds' : 'milliseconds', + now, + created, + diffInMinutes, + timeDiff: now - created + }); + + if (now - created < 1000) { + console.log('Setting loading to true for new link'); + setIsLoading(true); + } + + if (diffInMinutes < 2) { + const timeLeft = Math.ceil((2 - diffInMinutes) * 60 * 1000); + console.log('Setting timer for:', timeLeft, 'ms'); + const timer = setTimeout(() => { + console.log('Timer finished, setting loading to false'); + setIsLoading(false); + }, timeLeft); + + return () => clearTimeout(timer); + } }, [item.created_at]); const handleCopy = (text: string) => { - if (!canCopy) return; + if (isLoading) return; navigator.clipboard.writeText(text); }; @@ -77,21 +127,32 @@ export const AuditoryLink = ({ utmParams, item, index, onDelete }: AuditoryLinkP - handleCopy(linkText)} - > - - + {isLoading ? ( + + ) : ( + handleCopy(linkText)} + > + + + )} } > From a7c78e57e72d36052c38ad8a6f32adc74f6b976a Mon Sep 17 00:00:00 2001 From: Nastya Date: Tue, 10 Jun 2025 23:22:18 +0300 Subject: [PATCH 39/43] =?UTF-8?q?=D0=BD=D0=BE=D0=B2=D0=B0=D1=8F=20=D0=BB?= =?UTF-8?q?=D0=BE=D0=B3=D0=B8=D0=BA=D0=B0=20=D0=BE=D0=BF=D0=BB=D0=B0=D1=82?= =?UTF-8?q?=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PersonalizationAI/PersonalizationAI.tsx | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/pages/PersonalizationAI/PersonalizationAI.tsx b/src/pages/PersonalizationAI/PersonalizationAI.tsx index bb2bf0d9..8a5b4dd1 100644 --- a/src/pages/PersonalizationAI/PersonalizationAI.tsx +++ b/src/pages/PersonalizationAI/PersonalizationAI.tsx @@ -18,6 +18,8 @@ import { useToken } from "@frontend/kitui"; import { useSWRConfig } from "swr"; import { makeRequest } from "@api/makeRequest"; import { setUserAccount, setCustomerAccount } from "@/stores/user"; +import { quizApi } from "@api/quiz"; +import { setQuizes } from "@root/quizes/actions"; const tariff = "6844b8858258f5cc35791ef7"; export default function PersonalizationAI() { @@ -206,10 +208,10 @@ export default function PersonalizationAI() { setUtmParams(paramString ? `&${paramString}` : ""); }; - console.log("______-------__________---------_____---__--__-__--___------__--_---_--_----__--__-__--_--__--__--_---_______-privilegesOfUser") - console.log(privilegesOfUser) + console.log("______----giga_chat-----__--_---_--_----__--__-__--_--__--__--_---_______-quiz") + console.log(quiz?.giga_chat) const startCreate = async () => { - if (privilegesOfUser?.quizGigaChat && privilegesOfUser.quizGigaChat.amount > 0) { + if (quiz?.giga_chat) { createNewLink(); } else { setIsModalOpen(true); @@ -251,9 +253,25 @@ export default function PersonalizationAI() { //Развращаем товары в корзину inCart(); + //Показываем сообщение об успешной покупке + enqueueSnackbar("Тариф успешно приобретен", { variant: "success" }); + + + // Создаем новую ссылку после обновления данных + await createNewLink(); + + + // Обновляем данные квиза после успешной оплаты + console.log("Обновляем данные квиза после оплаты"); + const [quizes, quizesError] = await quizApi.getList(); + console.log("Получены данные квизов:", quizes); + if (!quizesError) { + setQuizes(quizes); + console.log("Данные квизов обновлены в сторе"); + } else { + console.error("Ошибка при получении данных квизов:", quizesError); + } - // Если покупка прошла успешно, создаем новую ссылку - createNewLink(); }; return ( From 8604daf6a4e6c03577a5295ceefc74430db2d72e Mon Sep 17 00:00:00 2001 From: Nastya Date: Sun, 15 Jun 2025 17:20:13 +0300 Subject: [PATCH 40/43] =?UTF-8?q?=D1=82=D1=83=D0=BB=D1=82=D0=B8=D0=BF=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D0=BF=D0=BE=D0=BA=D0=B0=D0=B7=D0=B0=20?= =?UTF-8?q?=D1=82=D0=B0=D0=B9=D0=BC=D0=B5=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/PersonalizationAI/AuditoryLink.tsx | 95 +---------- src/pages/PersonalizationAI/CopyButton.tsx | 161 +++++++++++++++++++ 2 files changed, 168 insertions(+), 88 deletions(-) create mode 100644 src/pages/PersonalizationAI/CopyButton.tsx diff --git a/src/pages/PersonalizationAI/AuditoryLink.tsx b/src/pages/PersonalizationAI/AuditoryLink.tsx index 0e17653f..8b4b9727 100644 --- a/src/pages/PersonalizationAI/AuditoryLink.tsx +++ b/src/pages/PersonalizationAI/AuditoryLink.tsx @@ -1,12 +1,11 @@ import { AuditoryItem } from "@/api/auditory"; -import CopyIcon from "@/assets/icons/CopyIcon"; import Trash from "@/assets/icons/trash"; import { useCurrentQuiz } from "@/stores/quizes/hooks"; import { InfoPopover } from "@/ui_kit/InfoPopover"; import TooltipClickInfo from "@/ui_kit/Toolbars/TooltipClickInfo"; import { useDomainDefine } from "@/utils/hooks/useDomainDefine"; -import { IconButton, ListItem, Skeleton, Typography, useTheme } from "@mui/material"; -import { useEffect, useMemo, useState } from "react"; +import { IconButton, ListItem, Typography, useTheme } from "@mui/material"; +import { CopyButton } from "./CopyButton"; interface AuditoryLinkProps { item: AuditoryItem; @@ -20,66 +19,7 @@ export const AuditoryLink = ({ utmParams, item, index, onDelete }: AuditoryLinkP const quiz = useCurrentQuiz(); const { isTestServer } = useDomainDefine(); - const getCreatedTime = (timestamp: number) => { - // Если timestamp в секундах (10 цифр) - if (timestamp.toString().length === 10) { - return new Date(timestamp * 1000).getTime(); - } - // Если timestamp в миллисекундах (13 цифр) - return new Date(timestamp).getTime(); - }; - - const [isLoading, setIsLoading] = useState(() => { - if (!item.created_at) return false; - const now = new Date().getTime(); - const created = getCreatedTime(item.created_at); - const diffInMinutes = (now - created) / (1000 * 60); - console.log('Initial state:', { - created_at: item.created_at, - format: item.created_at.toString().length === 10 ? 'seconds' : 'milliseconds', - now, - created, - diffInMinutes, - isLoading: diffInMinutes < 2 - }); - return diffInMinutes < 2; - }); - - useEffect(() => { - if (!item.created_at) return; - - const now = new Date().getTime(); - const created = getCreatedTime(item.created_at); - const diffInMinutes = (now - created) / (1000 * 60); - - console.log('Effect check:', { - created_at: item.created_at, - format: item.created_at.toString().length === 10 ? 'seconds' : 'milliseconds', - now, - created, - diffInMinutes, - timeDiff: now - created - }); - - if (now - created < 1000) { - console.log('Setting loading to true for new link'); - setIsLoading(true); - } - - if (diffInMinutes < 2) { - const timeLeft = Math.ceil((2 - diffInMinutes) * 60 * 1000); - console.log('Setting timer for:', timeLeft, 'ms'); - const timer = setTimeout(() => { - console.log('Timer finished, setting loading to false'); - setIsLoading(false); - }, timeLeft); - - return () => clearTimeout(timer); - } - }, [item.created_at]); - const handleCopy = (text: string) => { - if (isLoading) return; navigator.clipboard.writeText(text); }; @@ -127,32 +67,11 @@ export const AuditoryLink = ({ utmParams, item, index, onDelete }: AuditoryLinkP - {isLoading ? ( - - ) : ( - handleCopy(linkText)} - > - - - )} + } > diff --git a/src/pages/PersonalizationAI/CopyButton.tsx b/src/pages/PersonalizationAI/CopyButton.tsx new file mode 100644 index 00000000..9bcf0fe6 --- /dev/null +++ b/src/pages/PersonalizationAI/CopyButton.tsx @@ -0,0 +1,161 @@ +import { IconButton, Skeleton, useTheme, Tooltip, ClickAwayListener } from "@mui/material"; +import { useEffect, useState } from "react"; +import CopyIcon from "@/assets/icons/CopyIcon"; +import { useSnackbar } from "notistack"; + +interface CopyButtonProps { + created_at: number; + onCopy: (text: string) => void; + text: string; +} + +export const CopyButton = ({ created_at, onCopy, text }: CopyButtonProps) => { + const theme = useTheme(); + const { enqueueSnackbar } = useSnackbar(); + const [open, setOpen] = useState(false); + const [timeLeft, setTimeLeft] = useState(""); + + const getCreatedTime = (timestamp: number) => { + // Если timestamp в секундах (10 цифр) + if (timestamp.toString().length === 10) { + return new Date(timestamp * 1000).getTime(); + } + // Если timestamp в миллисекундах (13 цифр) + return new Date(timestamp).getTime(); + }; + + const formatTimeLeft = (milliseconds: number) => { + const minutes = Math.floor(milliseconds / (1000 * 60)); + const seconds = Math.floor((milliseconds % (1000 * 60)) / 1000); + return `${minutes}:${seconds.toString().padStart(2, '0')}`; + }; + + const [isLoading, setIsLoading] = useState(() => { + if (!created_at) return false; + const now = new Date().getTime(); + const created = getCreatedTime(created_at); + const diffInMinutes = (now - created) / (1000 * 60); + return diffInMinutes < 2; + }); + + useEffect(() => { + if (!created_at) return; + + const now = new Date().getTime(); + const created = getCreatedTime(created_at); + const diffInMinutes = (now - created) / (1000 * 60); + + if (now - created < 1000) { + setIsLoading(true); + } + + if (diffInMinutes < 2) { + const timeLeft = Math.ceil((2 - diffInMinutes) * 60 * 1000); + setTimeLeft(formatTimeLeft(timeLeft)); + + const timer = setInterval(() => { + const currentTime = new Date().getTime(); + const elapsed = currentTime - created; + const remaining = 2 * 60 * 1000 - elapsed; + + if (remaining <= 0) { + setIsLoading(false); + clearInterval(timer); + return; + } + + setTimeLeft(formatTimeLeft(remaining)); + }, 1000); + + return () => clearInterval(timer); + } + }, [created_at]); + + const handleClick = () => { + if (isLoading) return; + onCopy(text); + enqueueSnackbar("Ссылка успешно скопирована", { variant: "success" }); + }; + + const handleTooltipClose = () => { + setOpen(false); + }; + + const handleTooltipOpen = () => { + setOpen(true); + }; + + if (isLoading) { + return ( + +
+ + + +
+
+ ); + } + + return ( + + + + ); +}; \ No newline at end of file From 5ff3d7ae16a6ad89c145e0ead952f6724e5c26da Mon Sep 17 00:00:00 2001 From: Nastya Date: Sun, 15 Jun 2025 20:43:39 +0300 Subject: [PATCH 41/43] 3 min --- src/pages/PersonalizationAI/CopyButton.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/PersonalizationAI/CopyButton.tsx b/src/pages/PersonalizationAI/CopyButton.tsx index 9bcf0fe6..df82a2f5 100644 --- a/src/pages/PersonalizationAI/CopyButton.tsx +++ b/src/pages/PersonalizationAI/CopyButton.tsx @@ -35,7 +35,7 @@ export const CopyButton = ({ created_at, onCopy, text }: CopyButtonProps) => { const now = new Date().getTime(); const created = getCreatedTime(created_at); const diffInMinutes = (now - created) / (1000 * 60); - return diffInMinutes < 2; + return diffInMinutes < 3; }); useEffect(() => { @@ -49,14 +49,14 @@ export const CopyButton = ({ created_at, onCopy, text }: CopyButtonProps) => { setIsLoading(true); } - if (diffInMinutes < 2) { - const timeLeft = Math.ceil((2 - diffInMinutes) * 60 * 1000); + if (diffInMinutes < 3) { + const timeLeft = Math.ceil((3 - diffInMinutes) * 60 * 1000); setTimeLeft(formatTimeLeft(timeLeft)); const timer = setInterval(() => { const currentTime = new Date().getTime(); const elapsed = currentTime - created; - const remaining = 2 * 60 * 1000 - elapsed; + const remaining = 3 * 60 * 1000 - elapsed; if (remaining <= 0) { setIsLoading(false); From 5ad3a810ef8bcfdf9ee8b45e1d0266228805f608 Mon Sep 17 00:00:00 2001 From: Nastya Date: Mon, 16 Jun 2025 08:24:10 +0300 Subject: [PATCH 42/43] =?UTF-8?q?=D0=BE=D0=BF=D0=B8=D1=81=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cypress/e2e/personalization.cy.ts | 54 +++++++++++++++++++ jest.config.js | 15 ++++++ .../PersonalizationAI/PersonalizationAI.tsx | 17 ++++-- src/ui_kit/Toolbars/TooltipClickInfo.tsx | 12 +++-- 4 files changed, 91 insertions(+), 7 deletions(-) create mode 100644 cypress/e2e/personalization.cy.ts create mode 100644 jest.config.js diff --git a/cypress/e2e/personalization.cy.ts b/cypress/e2e/personalization.cy.ts new file mode 100644 index 00000000..cd4c13a8 --- /dev/null +++ b/cypress/e2e/personalization.cy.ts @@ -0,0 +1,54 @@ +/// + +describe('Personalization Flow', () => { + beforeEach(() => { + // Логинимся перед каждым тестом + cy.login(); // Предполагается, что у вас есть команда для логина + }); + + it('should complete personalization flow and open link in new tab', () => { + // Переходим на страницу персонализации + cy.visit('/personalization'); + + // Выбираем пол (мужской) + cy.get('[data-testid="gender-male"]').click(); + + // Генерируем случайный возраст от 1 до 99 + const randomAge = Math.floor(Math.random() * 99) + 1; + + // Вводим возраст + cy.get('[data-testid="age-input"]') + .type(randomAge.toString()) + .should('have.value', randomAge.toString()); + + // Нажимаем кнопку OK + cy.get('[data-testid="submit-button"]').click(); + + // Ждем появления скелетона загрузки + cy.get('[data-testid="loading-skeleton"]').should('be.visible'); + + // Ждем 3 минуты (в реальном тесте это будет быстрее из-за моков) + cy.wait(180000); + + // Ждем появления кнопки копирования + cy.get('[data-testid="copy-button"]').should('be.visible'); + + // Копируем ссылку + cy.get('[data-testid="copy-button"]').click(); + + // Проверяем появление уведомления об успешном копировании + cy.contains('Ссылка успешно скопирована').should('be.visible'); + + // Получаем ссылку из буфера обмена + cy.window().then((win) => { + win.navigator.clipboard.readText().then((text) => { + // Открываем ссылку в новой вкладке + cy.window().then((win) => { + const newWindow = win.open(text, '_blank'); + // Проверяем, что новая вкладка открылась + expect(newWindow).to.not.be.null; + }); + }); + }); + }); +}); diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 00000000..b51269e5 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,15 @@ +module.exports = { + transformIgnorePatterns: [ + '/node_modules/(?!(@frontend/kitui|@frontend/squzanswerer)/)' + ], + moduleNameMapper: { + '^@/(.*)$': '/src/$1', + '^@utils/(.*)$': '/src/utils/$1', + '^@assets/(.*)$': '/src/assets/$1' + }, + setupFilesAfterEnv: ['/src/setupTests.ts'], + testEnvironment: 'jsdom', + transform: { + '^.+\\.(ts|tsx)$': 'ts-jest' + } +}; \ No newline at end of file diff --git a/src/pages/PersonalizationAI/PersonalizationAI.tsx b/src/pages/PersonalizationAI/PersonalizationAI.tsx index 8a5b4dd1..065d7b4c 100644 --- a/src/pages/PersonalizationAI/PersonalizationAI.tsx +++ b/src/pages/PersonalizationAI/PersonalizationAI.tsx @@ -20,6 +20,7 @@ import { makeRequest } from "@api/makeRequest"; import { setUserAccount, setCustomerAccount } from "@/stores/user"; import { quizApi } from "@api/quiz"; import { setQuizes } from "@root/quizes/actions"; +import TooltipClickInfo from "@/ui_kit/Toolbars/TooltipClickInfo"; const tariff = "6844b8858258f5cc35791ef7"; export default function PersonalizationAI() { @@ -287,8 +288,13 @@ export default function PersonalizationAI() { wordSpacing: "0.1px", lineHeight: "21.4px" }}> - Данный раздел позволяет вам создавать персонализированный опрос под каждую целевую аудиторию отдельно, наш AI перефразирует ваши вопросы согласно настройкам. Для этого нужно выбрать пол и возраст вашей аудитории и получите персональную ссылку с нужными настройками в списке ниже. Так же вы можете обогатить свою ссылку UTM метками - {/* Первый белый блок */} +Данный раздел позволяет вам создавать персонализированный опрос под каждую целевую аудиторию отдельно, наш AI перефразирует ваши вопросы согласно настройкам. +Для этого нужно выбрать пол и возраст вашей аудитории и получите персональную ссылку с нужными настройками в списке ниже. + +Так же вы можете обогатить свою ссылку UTM метками в поле "вставьте свою ссылку"и этим метки применятся ко всем вашим ссылкам. + +ВАЖНО: если ваши вопросы уже подходят целевой аудитории, то персонализированы они скорее всего не будут. {/* Первый белый блок */} + Ссылка - + + {/* + + Данное поле создано для обогащения utm метками вашей ссылки. Нужно скопировать ссылку вашего квиза, задать настройки ца, вставить ссылку в поле, прописать метки(советуем использовать динамические), и нажать "ок" выше поля. Метки будут применены ко всем ссылкам с персонализацией в рамках данного квиза. + + */} From 25deb4a0f4c1d481c631cca5ec81374157e138bc Mon Sep 17 00:00:00 2001 From: Nastya Date: Wed, 18 Jun 2025 00:23:50 +0300 Subject: [PATCH 43/43] =?UTF-8?q?=D0=B5=D1=81=D1=82=D1=8C=20id=20=D1=82?= =?UTF-8?q?=D0=B0=D1=80=D0=B8=D1=84=D0=B0=20=D0=B4=D0=BB=D1=8F=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D0=B4=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cypress.config.ts | 21 +- cypress/e2e/personalization.cy.ts | 87 ++- cypress/support/commands.ts | 28 + cypress/support/e2e.ts | 13 + package.json | 6 +- src/pages/PersonalizationAI/AuditoryLink.tsx | 5 +- .../PersonalizationAI/PersonalizationAI.tsx | 4 +- yarn.lock | 722 +++++++++++++++++- 8 files changed, 824 insertions(+), 62 deletions(-) create mode 100644 cypress/support/commands.ts create mode 100644 cypress/support/e2e.ts diff --git a/cypress.config.ts b/cypress.config.ts index 87067adb..2a383c70 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -3,8 +3,23 @@ import { defineConfig } from "cypress"; export default defineConfig({ e2e: { baseUrl: 'http://localhost:3000', - viewportWidth: 1440, - viewportHeight: 900, - supportFile: false, + viewportWidth: 1280, + viewportHeight: 720, + video: true, + screenshotOnRunFailure: true, + supportFile: 'cypress/support/e2e.ts', + defaultCommandTimeout: 10000, + pageLoadTimeout: 30000, + requestTimeout: 10000, + responseTimeout: 30000, + setupNodeEvents(on, config) { + // implement node event listeners here + }, + }, + component: { + devServer: { + framework: 'react', + bundler: 'vite', + }, }, }); diff --git a/cypress/e2e/personalization.cy.ts b/cypress/e2e/personalization.cy.ts index cd4c13a8..6a51a5c8 100644 --- a/cypress/e2e/personalization.cy.ts +++ b/cypress/e2e/personalization.cy.ts @@ -3,52 +3,73 @@ describe('Personalization Flow', () => { beforeEach(() => { // Логинимся перед каждым тестом - cy.login(); // Предполагается, что у вас есть команда для логина + cy.login(); }); it('should complete personalization flow and open link in new tab', () => { - // Переходим на страницу персонализации - cy.visit('/personalization'); + // Ищем нужный квиз и нажимаем редактировать + cy.contains('Сочетание перестановки и размещения') + .parent() + .parent() + .contains('Редактировать') + .click(); - // Выбираем пол (мужской) - cy.get('[data-testid="gender-male"]').click(); + // Переходим на вкладку персонализации + cy.contains('Персонализация').click(); + + // Ждем загрузки данных + cy.get('.MuiSkeleton-root', { timeout: 30000 }).should('not.exist'); + cy.wait(6000); + + // Удаляем все существующие ссылки + cy.get('body').then(($body) => { + if ($body.find('.delete_aud').length > 0) { + // Пока есть кнопки удаления - удаляем ссылки + const deleteLinks = () => { + // Находим первую кнопку удаления и кликаем по ней + cy.get('.delete_aud').first().click(); + // Подтверждаем удаление + cy.get('#delete_OK').click(); + // Проверяем, остались ли еще кнопки удаления + cy.get('body').then(($body) => { + if ($body.find('.delete_aud').length > 0) { + deleteLinks(); + } + }); + }; + deleteLinks(); + } + }); + + // Выбираем пол (М) + cy.contains('М').click(); // Генерируем случайный возраст от 1 до 99 const randomAge = Math.floor(Math.random() * 99) + 1; // Вводим возраст - cy.get('[data-testid="age-input"]') + cy.get('input[placeholder="Введите возраст"]') .type(randomAge.toString()) .should('have.value', randomAge.toString()); - // Нажимаем кнопку OK - cy.get('[data-testid="submit-button"]').click(); + // Нажимаем кнопку Ок + cy.contains('Ок').click(); - // Ждем появления скелетона загрузки - cy.get('[data-testid="loading-skeleton"]').should('be.visible'); - - // Ждем 3 минуты (в реальном тесте это будет быстрее из-за моков) - cy.wait(180000); - - // Ждем появления кнопки копирования - cy.get('[data-testid="copy-button"]').should('be.visible'); - - // Копируем ссылку - cy.get('[data-testid="copy-button"]').click(); - - // Проверяем появление уведомления об успешном копировании - cy.contains('Ссылка успешно скопирована').should('be.visible'); - - // Получаем ссылку из буфера обмена - cy.window().then((win) => { - win.navigator.clipboard.readText().then((text) => { - // Открываем ссылку в новой вкладке - cy.window().then((win) => { - const newWindow = win.open(text, '_blank'); - // Проверяем, что новая вкладка открылась - expect(newWindow).to.not.be.null; - }); + // Ждем появления ссылки и получаем её текст + cy.get('.link', { timeout: 30000 }) + .should('be.visible') + .invoke('text') + .then((text) => { + // Исправляем домен в ссылке + const url = new URL(text); + url.hostname = 's.hbpn.link'; + const correctUrl = url.toString(); + + // Переходим на страницу по исправленной ссылке + cy.visit(correctUrl); + + // Проверяем содержимое страницы + cy.contains('Сочетание перестановки и размещения').should('exist'); }); - }); }); }); diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts new file mode 100644 index 00000000..f58ee6c2 --- /dev/null +++ b/cypress/support/commands.ts @@ -0,0 +1,28 @@ +/// + +declare global { + namespace Cypress { + interface Chainable { + login(): Chainable + } + } +} + +Cypress.Commands.add('login', () => { + // Пробуем перейти на страницу входа + cy.visit('/signin', { + timeout: 10000, // Увеличиваем таймаут до 10 секунд + failOnStatusCode: false // Не падаем при ошибках статуса + }); + + // Проверяем, что мы на странице входа + cy.url().should('include', '/signin'); + + // Вводим данные для входа + cy.get('#email', { timeout: 10000 }).should('be.visible').type('test@test.ru'); + cy.get('#password', { timeout: 10000 }).should('be.visible').type('testtest'); + cy.get('button[type="submit"]', { timeout: 10000 }).should('be.visible').click(); + + // Ждем успешного входа + cy.url().should('not.include', '/signin', { timeout: 10000 }); +}); \ No newline at end of file diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.ts new file mode 100644 index 00000000..7c16f0c9 --- /dev/null +++ b/cypress/support/e2e.ts @@ -0,0 +1,13 @@ +// Import commands.js using ES2015 syntax: +import './commands'; + +// Alternatively you can use CommonJS syntax: +// require('./commands') + +declare global { + namespace Cypress { + interface Chainable { + login(): Chainable + } + } +} \ No newline at end of file diff --git a/package.json b/package.json index d93a1b7f..5f34f899 100755 --- a/package.json +++ b/package.json @@ -69,7 +69,9 @@ "test": "craco test", "eject": "craco eject", "code:format": "prettier --write --ignore-unknown", - "prepare": "husky install" + "prepare": "husky install", + "cypress:open": "cypress open", + "cypress:run": "cypress run" }, "browserslist": { "production": [ @@ -86,10 +88,12 @@ "devDependencies": { "@emoji-mart/data": "^1.2.1", "@emoji-mart/react": "^1.1.1", + "@types/cypress": "^1.1.6", "@types/cytoscape-popper": "^2.0.4", "@types/react-beautiful-dnd": "^13.1.4", "@types/react-cytoscapejs": "^1.2.4", "craco-alias": "^3.0.1", + "cypress": "^14.4.1", "husky": "^8.0.3", "lint-staged": "^15.2.0", "prettier": "^3.1.1" diff --git a/src/pages/PersonalizationAI/AuditoryLink.tsx b/src/pages/PersonalizationAI/AuditoryLink.tsx index 8b4b9727..66ed1213 100644 --- a/src/pages/PersonalizationAI/AuditoryLink.tsx +++ b/src/pages/PersonalizationAI/AuditoryLink.tsx @@ -53,6 +53,7 @@ export const AuditoryLink = ({ utmParams, item, index, onDelete }: AuditoryLinkP secondaryAction={ <> } > - ([]); @@ -376,7 +376,7 @@ export default function PersonalizationAI() { }} > Уверены, что хотите удалить ссылку? - + diff --git a/yarn.lock b/yarn.lock index 55a535c0..00050294 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1235,6 +1235,38 @@ resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz#2cbcf822bf3764c9658c4d2e568bd0c0cb748016" integrity sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw== +"@cypress/request@^3.0.8": + version "3.0.8" + resolved "https://registry.npmjs.org/@cypress/request/-/request-3.0.8.tgz#992f1f42ba03ebb14fa5d97290abe9d015ed0815" + integrity sha512-h0NFgh1mJmm1nr4jCwkGHwKneVYKghUyWe6TMNrk0B9zsjAJxpg8C4/+BAcmLgCPa1vj1V8rNUaILl+zYRUWBQ== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~4.0.0" + http-signature "~1.4.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + performance-now "^2.1.0" + qs "6.14.0" + safe-buffer "^5.1.2" + tough-cookie "^5.0.0" + tunnel-agent "^0.6.0" + uuid "^8.3.2" + +"@cypress/xvfb@^1.2.4": + version "1.2.4" + resolved "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz#2daf42e8275b39f4aa53c14214e557bd14e7748a" + integrity sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q== + dependencies: + debug "^3.1.0" + lodash.once "^4.1.1" + "@emoji-mart/data@^1.2.1": version "1.2.1" resolved "https://registry.yarnpkg.com/@emoji-mart/data/-/data-1.2.1.tgz#0ad70c662e3bc603e23e7d98413bd1e64c4fcb6c" @@ -2346,6 +2378,13 @@ dependencies: "@types/node" "*" +"@types/cypress@^1.1.6": + version "1.1.6" + resolved "https://registry.npmjs.org/@types/cypress/-/cypress-1.1.6.tgz#b190688acffb847a3f5c4cee15c82d4f2a342ee6" + integrity sha512-CfeLLD3+6vIWe2AO5hR63f1c8EbRzrp/j1ExubAwOTpwZFZvF3Nm9cOPQiUwzNmAUmZuhO0QVH98Qlujni6nPw== + dependencies: + cypress "*" + "@types/cytoscape-popper@^2.0.4": version "2.0.4" resolved "https://registry.yarnpkg.com/@types/cytoscape-popper/-/cytoscape-popper-2.0.4.tgz#cd1e81d28b202e2bfc5608e0e60ae53c908bf0e3" @@ -2680,6 +2719,16 @@ "@types/node" "*" "@types/send" "*" +"@types/sinonjs__fake-timers@8.1.1": + version "8.1.1" + resolved "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz#b49c2c70150141a15e0fa7e79cf1f92a72934ce3" + integrity sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g== + +"@types/sizzle@^2.3.2": + version "2.3.9" + resolved "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.9.tgz#d4597dbd4618264c414d7429363e3f50acb66ea2" + integrity sha512-xzLEyKB50yqCUPUJkIsrVvoWNfFUbIZI+RspLWt8u+tIW/BetMBZtgV2LY/2o+tYH8dRvQ+eoPf3NdhQCcLE2w== + "@types/sockjs@^0.3.33": version "0.3.36" resolved "https://registry.yarnpkg.com/@types/sockjs/-/sockjs-0.3.36.tgz#ce322cf07bcc119d4cbf7f88954f3a3bd0f67535" @@ -2730,6 +2779,13 @@ dependencies: "@types/yargs-parser" "*" +"@types/yauzl@^2.9.1": + version "2.10.3" + resolved "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz#e9b2808b4f109504a03cda958259876f61017999" + integrity sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q== + dependencies: + "@types/node" "*" + "@typescript-eslint/eslint-plugin@^5.5.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz#aeef0328d172b9e37d9bab6dbc13b87ed88977db" @@ -3025,6 +3081,14 @@ agent-base@6: dependencies: debug "4" +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + ajv-formats@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" @@ -3064,7 +3128,12 @@ ajv@^8.0.0, ajv@^8.6.0, ajv@^8.9.0: json-schema-traverse "^1.0.0" require-from-string "^2.0.2" -ansi-escapes@^4.2.1, ansi-escapes@^4.3.1: +ansi-colors@^4.1.1: + version "4.1.3" + resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== + +ansi-escapes@^4.2.1, ansi-escapes@^4.3.0, ansi-escapes@^4.3.1: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== @@ -3135,6 +3204,11 @@ anymatch@^3.0.3, anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" +arch@^2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" + integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ== + arg@^4.1.0: version "4.1.3" resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" @@ -3287,17 +3361,34 @@ asap@~2.0.6: resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== +asn1@~0.2.3: + version "0.2.6" + resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" + integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== + ast-types-flow@^0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.8.tgz#0a85e1c92695769ac13a428bb653e7538bea27d6" integrity sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ== +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + async-function@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async-function/-/async-function-1.0.0.tgz#509c9fca60eaf85034c6829838188e4e4c8ffb2b" integrity sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA== -async@^3.2.3: +async@^3.2.0, async@^3.2.3: version "3.2.6" resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== @@ -3331,6 +3422,16 @@ available-typed-arrays@^1.0.7: dependencies: possible-typed-array-names "^1.0.0" +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA== + +aws4@^1.8.0: + version "1.13.2" + resolved "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz#0aa167216965ac9474ccfa83892cfb6b3e1e52ef" + integrity sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw== + axe-core@^4.10.0: version "4.10.3" resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.10.3.tgz#04145965ac7894faddbac30861e5d8f11bfd14fc" @@ -3495,11 +3596,23 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + batch@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" integrity sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw== +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w== + dependencies: + tweetnacl "^0.14.3" + bfj@^7.0.2: version "7.1.0" resolved "https://registry.yarnpkg.com/bfj/-/bfj-7.1.0.tgz#c5177d522103f9040e1b12980fe8c38cf41d3f8b" @@ -3521,6 +3634,11 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== +blob-util@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz#3b4e3c281111bb7f11128518006cdc60b403a1eb" + integrity sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ== + bluebird@^3.7.2: version "3.7.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" @@ -3606,11 +3724,24 @@ bser@2.1.1: dependencies: node-int64 "^0.4.0" +buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== + buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== +buffer@^5.7.1: + version "5.7.1" + resolved "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + builtin-modules@^3.1.0: version "3.3.0" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" @@ -3621,6 +3752,11 @@ bytes@3.1.2: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== +cachedir@^2.3.0: + version "2.4.0" + resolved "https://registry.npmjs.org/cachedir/-/cachedir-2.4.0.tgz#7fef9cf7367233d7c88068fe6e34ed0d355a610d" + integrity sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ== + call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" @@ -3695,6 +3831,11 @@ case-sensitive-paths-webpack-plugin@^2.4.0: resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz#db64066c6422eed2e08cc14b986ca43796dbc6d4" integrity sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw== +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== + chalk@^2.4.1: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -3735,6 +3876,11 @@ char-regex@^2.0.0: resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-2.0.2.tgz#81385bb071af4df774bff8721d0ca15ef29ea0bb" integrity sha512-cbGOjAptfM2LVmWhwRFHEKTPkLwNddVmuqYZQt895yXwAsWsXObCG+YN4DGQ/JBtT4GP1a1lPPdio2z413LmTg== +check-more-types@^2.24.0: + version "2.24.0" + resolved "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz#1420ffb10fd444dcfc79b43891bbfffd32a84600" + integrity sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA== + check-types@^11.2.3: version "11.2.3" resolved "https://registry.yarnpkg.com/check-types/-/check-types-11.2.3.tgz#1ffdf68faae4e941fce252840b1787b8edc93b71" @@ -3765,6 +3911,11 @@ ci-info@^3.2.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== +ci-info@^4.1.0: + version "4.2.0" + resolved "https://registry.npmjs.org/ci-info/-/ci-info-4.2.0.tgz#cbd21386152ebfe1d56f280a3b5feccbd96764c7" + integrity sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg== + cjs-module-lexer@^1.0.0: version "1.4.3" resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz#0f79731eb8cfe1ec72acd4066efac9d61991b00d" @@ -3782,6 +3933,18 @@ clean-css@^5.2.2: dependencies: source-map "~0.6.0" +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + cli-cursor@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-5.0.0.tgz#24a4831ecf5a6b01ddeb32fb71a4b2088b0dce38" @@ -3789,6 +3952,23 @@ cli-cursor@^5.0.0: dependencies: restore-cursor "^5.0.0" +cli-table3@0.6.1: + version "0.6.1" + resolved "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.1.tgz#36ce9b7af4847f288d3cdd081fbd09bf7bd237b8" + integrity sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA== + dependencies: + string-width "^4.2.0" + optionalDependencies: + colors "1.4.0" + +cli-truncate@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" + integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg== + dependencies: + slice-ansi "^3.0.0" + string-width "^4.2.0" + cli-truncate@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-4.0.0.tgz#6cc28a2924fee9e25ce91e973db56c7066e6172a" @@ -3882,12 +4062,17 @@ colord@^2.9.1: resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43" integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw== -colorette@^2.0.10, colorette@^2.0.20: +colorette@^2.0.10, colorette@^2.0.16, colorette@^2.0.20: version "2.0.20" resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== -combined-stream@^1.0.8: +colors@1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" + integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== + +combined-stream@^1.0.8, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== @@ -3909,6 +4094,11 @@ commander@^4.0.0: resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== +commander@^6.2.1: + version "6.2.1" + resolved "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" + integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== + commander@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" @@ -4013,6 +4203,11 @@ core-js@^3.19.2: resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.41.0.tgz#57714dafb8c751a6095d028a7428f1fb5834a776" integrity sha512-SJ4/EHwS36QMJd6h/Rg+GyR4A5xE0FSI3eZ+iBVpfqf1x0eTSg1smWLHrA+2jQThZSh97fmSgFSU8B61nxosxA== +core-util-is@1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== + core-util-is@~1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" @@ -4068,7 +4263,7 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cross-spawn@^7.0.2, cross-spawn@^7.0.3, cross-spawn@^7.0.6: +cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3, cross-spawn@^7.0.6: version "7.0.6" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== @@ -4289,6 +4484,55 @@ current-device@^0.10.2: resolved "https://registry.yarnpkg.com/current-device/-/current-device-0.10.2.tgz#1e40176bee7da655383ab7245b853fae7d2dfc8e" integrity sha512-FN223n2Cp1fRI/gyjJEAdagHhJ/2Z2STz3tUg1t4F259BhmVRCChkmxcgFtjYJsWuIacQEs7bqJpnAczIXIkWw== +cypress@*, cypress@^14.4.1: + version "14.4.1" + resolved "https://registry.npmjs.org/cypress/-/cypress-14.4.1.tgz#6e586ba098503b594561d5f8f746a9db6556ed2a" + integrity sha512-YSGvVXtTqSGRTyHbaxHI5dHU/9xc5ymaTIM4BU85GKhj980y6XgA3fShSpj5DatS8knXMsAvYItQxVQFHGpUtw== + dependencies: + "@cypress/request" "^3.0.8" + "@cypress/xvfb" "^1.2.4" + "@types/sinonjs__fake-timers" "8.1.1" + "@types/sizzle" "^2.3.2" + arch "^2.2.0" + blob-util "^2.0.2" + bluebird "^3.7.2" + buffer "^5.7.1" + cachedir "^2.3.0" + chalk "^4.1.0" + check-more-types "^2.24.0" + ci-info "^4.1.0" + cli-cursor "^3.1.0" + cli-table3 "0.6.1" + commander "^6.2.1" + common-tags "^1.8.0" + dayjs "^1.10.4" + debug "^4.3.4" + enquirer "^2.3.6" + eventemitter2 "6.4.7" + execa "4.1.0" + executable "^4.1.1" + extract-zip "2.0.1" + figures "^3.2.0" + fs-extra "^9.1.0" + getos "^3.2.1" + is-installed-globally "~0.4.0" + lazy-ass "^1.6.0" + listr2 "^3.8.3" + lodash "^4.17.21" + log-symbols "^4.0.0" + minimist "^1.2.8" + ospath "^1.2.2" + pretty-bytes "^5.6.0" + process "^0.11.10" + proxy-from-env "1.0.0" + request-progress "^3.0.0" + semver "^7.7.1" + supports-color "^8.1.1" + tmp "~0.2.3" + tree-kill "1.2.2" + untildify "^4.0.0" + yauzl "^2.10.0" + cytoscape-popper@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/cytoscape-popper/-/cytoscape-popper-2.0.0.tgz#d93917695a9b8af3dbda1d8ee433618ac4d4e359" @@ -4367,6 +4611,13 @@ damerau-levenshtein@^1.0.8: resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA== +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g== + dependencies: + assert-plus "^1.0.0" + data-urls@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" @@ -4408,6 +4659,11 @@ date-fns@^3.0.6: resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-3.6.0.tgz#f20ca4fe94f8b754951b24240676e8618c0206bf" integrity sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww== +dayjs@^1.10.4: + version "1.11.13" + resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" + integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== + debug@2.6.9, debug@^2.6.0: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -4422,7 +4678,7 @@ debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, d dependencies: ms "^2.1.3" -debug@^3.2.7: +debug@^3.1.0, debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== @@ -4728,6 +4984,14 @@ eastasianwidth@^0.2.0: resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw== + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -4790,6 +5054,13 @@ encodeurl@~2.0.0: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== +end-of-stream@^1.1.0: + version "1.4.5" + resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz#7344d711dea40e0b74abc2ed49778743ccedb08c" + integrity sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg== + dependencies: + once "^1.4.0" + enhanced-resolve@^5.17.1: version "5.18.1" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz#728ab082f8b7b6836de51f1637aab5d3b9568faf" @@ -4803,6 +5074,14 @@ enquire.js@^2.1.6: resolved "https://registry.yarnpkg.com/enquire.js/-/enquire.js-2.1.6.tgz#3e8780c9b8b835084c3f60e166dbc3c2a3c89814" integrity sha512-/KujNpO+PT63F7Hlpu4h3pE3TokKRHN26JYmQpPyjkRD/N57R7bPDNojMXdi7uveAKjYB7yQnartCxZnFWr0Xw== +enquirer@^2.3.6: + version "2.4.1" + resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz#93334b3fbd74fc7097b224ab4a8fb7e40bf4ae56" + integrity sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ== + dependencies: + ansi-colors "^4.1.1" + strip-ansi "^6.0.1" + entities@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" @@ -5294,6 +5573,11 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== +eventemitter2@6.4.7: + version "6.4.7" + resolved "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz#a7f6c4d7abf28a14c1ef3442f21cb306a054271d" + integrity sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg== + eventemitter3@^4.0.0: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" @@ -5309,6 +5593,21 @@ events@^3.2.0: resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== +execa@4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" + integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== + dependencies: + cross-spawn "^7.0.0" + get-stream "^5.0.0" + human-signals "^1.1.1" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.0" + onetime "^5.1.0" + signal-exit "^3.0.2" + strip-final-newline "^2.0.0" + execa@^5.0.0: version "5.1.1" resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" @@ -5339,6 +5638,13 @@ execa@^8.0.1: signal-exit "^4.1.0" strip-final-newline "^3.0.0" +executable@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz#41532bff361d3e57af4d763b70582db18f5d133c" + integrity sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg== + dependencies: + pify "^2.2.0" + exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -5402,6 +5708,32 @@ express@^4.17.3: utils-merge "1.0.1" vary "~1.1.2" +extend@~3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +extract-zip@2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" + integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== + dependencies: + debug "^4.1.1" + get-stream "^5.1.0" + yauzl "^2.10.0" + optionalDependencies: + "@types/yauzl" "^2.9.1" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g== + +extsprintf@^1.2.0: + version "1.4.1" + resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" + integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== + fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -5454,6 +5786,20 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" +fd-slicer@~1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" + integrity sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g== + dependencies: + pend "~1.2.0" + +figures@^3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -5582,6 +5928,11 @@ foreground-child@^3.1.0: cross-spawn "^7.0.6" signal-exit "^4.0.1" +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== + fork-ts-checker-webpack-plugin@^6.5.0: version "6.5.3" resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz#eda2eff6e22476a2688d10661688c47f611b37f3" @@ -5621,6 +5972,17 @@ form-data@^4.0.0: es-set-tostringtag "^2.1.0" mime-types "^2.1.12" +form-data@~4.0.0: + version "4.0.3" + resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz#608b1b3f3e28be0fccf5901fc85fb3641e5cf0ae" + integrity sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + es-set-tostringtag "^2.1.0" + hasown "^2.0.2" + mime-types "^2.1.12" + formik@^2.4.5: version "2.4.6" resolved "https://registry.yarnpkg.com/formik/-/formik-2.4.6.tgz#4da75ca80f1a827ab35b08fd98d5a76e928c9686" @@ -5659,7 +6021,7 @@ fs-extra@^10.0.0: jsonfile "^6.0.1" universalify "^2.0.0" -fs-extra@^9.0.0, fs-extra@^9.0.1: +fs-extra@^9.0.0, fs-extra@^9.0.1, fs-extra@^9.1.0: version "9.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== @@ -5755,6 +6117,13 @@ get-proto@^1.0.0, get-proto@^1.0.1: dunder-proto "^1.0.1" es-object-atoms "^1.0.0" +get-stream@^5.0.0, get-stream@^5.1.0: + version "5.2.0" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + get-stream@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" @@ -5774,6 +6143,20 @@ get-symbol-description@^1.1.0: es-errors "^1.3.0" get-intrinsic "^1.2.6" +getos@^3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz#0134d1f4e00eb46144c5a9c0ac4dc087cbb27dc5" + integrity sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q== + dependencies: + async "^3.2.0" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng== + dependencies: + assert-plus "^1.0.0" + glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" @@ -5817,6 +6200,13 @@ glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" +global-dirs@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz#0c488971f066baceda21447aecb1a8b911d22485" + integrity sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA== + dependencies: + ini "2.0.0" + global-modules@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" @@ -6098,6 +6488,15 @@ http-proxy@^1.18.1: follow-redirects "^1.0.0" requires-port "^1.0.0" +http-signature@~1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.4.0.tgz#dee5a9ba2bf49416abc544abd6d967f6a94c8c3f" + integrity sha512-G5akfn7eKbpDN+8nPS/cb57YeA1jLTVxjpCj7tmm3QKPdyDy7T+qSC40e9ptydSWvkwjSXw1VbkpyEm39ukeAg== + dependencies: + assert-plus "^1.0.0" + jsprim "^2.0.2" + sshpk "^1.18.0" + https-proxy-agent@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" @@ -6106,6 +6505,11 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" +human-signals@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" + integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== + human-signals@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" @@ -6152,6 +6556,11 @@ identity-obj-proxy@^3.0.0: dependencies: harmony-reflect "^1.4.6" +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + ignore@^5.2.0: version "5.3.2" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" @@ -6223,6 +6632,11 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== +ini@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" + integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== + ini@^1.3.5: version "1.3.8" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" @@ -6406,6 +6820,14 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" +is-installed-globally@~0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520" + integrity sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ== + dependencies: + global-dirs "^3.0.0" + is-path-inside "^3.0.2" + is-map@^2.0.2, is-map@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" @@ -6434,7 +6856,7 @@ is-obj@^1.0.1: resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" integrity sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg== -is-path-inside@^3.0.3: +is-path-inside@^3.0.2, is-path-inside@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== @@ -6522,11 +6944,16 @@ is-typed-array@^1.1.13, is-typed-array@^1.1.14, is-typed-array@^1.1.15: dependencies: which-typed-array "^1.1.16" -is-typedarray@^1.0.0: +is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + is-weakmap@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd" @@ -6574,6 +7001,11 @@ isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== + istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" @@ -7206,6 +7638,11 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== + jsdom@^16.6.0: version "16.7.0" resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" @@ -7269,7 +7706,7 @@ json-schema-traverse@^1.0.0: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== -json-schema@^0.4.0: +json-schema@0.4.0, json-schema@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== @@ -7279,6 +7716,11 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== + json2mq@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/json2mq/-/json2mq-0.2.0.tgz#b637bd3ba9eabe122c83e9720483aeb10d2c904a" @@ -7321,6 +7763,16 @@ jsonpointer@^5.0.0: resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-5.0.1.tgz#2110e0af0900fd37467b5907ecd13a7884a1b559" integrity sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ== +jsprim@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz#77ca23dbcd4135cd364800d22ff82c2185803d4d" + integrity sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ== + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.4.0" + verror "1.10.0" + "jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.5: version "3.3.5" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz#4766bd05a8e2a11af222becd19e15575e52a853a" @@ -7383,6 +7835,11 @@ launch-editor@^2.6.0: picocolors "^1.0.0" shell-quote "^1.8.1" +lazy-ass@^1.6.0: + version "1.6.0" + resolved "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz#7999655e8646c17f089fdd187d150d3324d54513" + integrity sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw== + leven@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" @@ -7447,6 +7904,20 @@ lint-staged@^15.2.0: string-argv "^0.3.2" yaml "^2.7.0" +listr2@^3.8.3: + version "3.14.0" + resolved "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz#23101cc62e1375fd5836b248276d1d2b51fdbe9e" + integrity sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g== + dependencies: + cli-truncate "^2.1.0" + colorette "^2.0.16" + log-update "^4.0.0" + p-map "^4.0.0" + rfdc "^1.3.0" + rxjs "^7.5.1" + through "^2.3.8" + wrap-ansi "^7.0.0" + listr2@^8.2.5: version "8.2.5" resolved "https://registry.yarnpkg.com/listr2/-/listr2-8.2.5.tgz#5c9db996e1afeb05db0448196d3d5f64fec2593d" @@ -7520,6 +7991,11 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== +lodash.once@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== + lodash.sortby@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" @@ -7535,6 +8011,24 @@ lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== +log-symbols@^4.0.0: + version "4.1.0" + resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +log-update@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" + integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg== + dependencies: + ansi-escapes "^4.3.0" + cli-cursor "^3.1.0" + slice-ansi "^4.0.0" + wrap-ansi "^6.2.0" + log-update@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/log-update/-/log-update-6.1.0.tgz#1a04ff38166f94647ae1af562f4bd6a15b1b7cd4" @@ -7680,7 +8174,7 @@ mime-db@1.52.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.54.0.tgz#cddb3ee4f9c64530dff640236661d42cb6a314f5" integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ== -mime-types@^2.1.12, mime-types@^2.1.27, mime-types@^2.1.31, mime-types@^2.1.35, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34: +mime-types@^2.1.12, mime-types@^2.1.27, mime-types@^2.1.31, mime-types@^2.1.35, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== @@ -7746,7 +8240,7 @@ minimatch@^9.0.4: dependencies: brace-expansion "^2.0.1" -minimist@^1.2.0, minimist@^1.2.6: +minimist@^1.2.0, minimist@^1.2.6, minimist@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -7894,7 +8388,7 @@ notistack@^3.0.1: clsx "^1.1.0" goober "^2.0.33" -npm-run-path@^4.0.1: +npm-run-path@^4.0.0, npm-run-path@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== @@ -8036,14 +8530,14 @@ on-headers@~1.0.2: resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== -once@^1.3.0: +once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" -onetime@^5.1.2: +onetime@^5.1.0, onetime@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== @@ -8097,6 +8591,11 @@ optionator@^0.9.3: type-check "^0.4.0" word-wrap "^1.2.5" +ospath@^1.2.2: + version "1.2.2" + resolved "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz#1276639774a3f8ef2572f7fe4280e0ea4550c07b" + integrity sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA== + own-keys@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/own-keys/-/own-keys-1.0.1.tgz#e4006910a2bf913585289676eebd6f390cf51358" @@ -8141,6 +8640,13 @@ p-locate@^5.0.0: dependencies: p-limit "^3.0.2" +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + p-retry@^4.5.0: version "4.6.2" resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-4.6.2.tgz#9baae7184057edd4e17231cee04264106e092a16" @@ -8255,6 +8761,11 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== + performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" @@ -8280,7 +8791,7 @@ pidtree@^0.6.0: resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c" integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== -pify@^2.3.0: +pify@^2.2.0, pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== @@ -8884,7 +9395,7 @@ prettier@^3.1.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.5.3.tgz#4fc2ce0d657e7a02e602549f053b239cb7dfe1b5" integrity sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw== -pretty-bytes@^5.3.0, pretty-bytes@^5.4.1: +pretty-bytes@^5.3.0, pretty-bytes@^5.4.1, pretty-bytes@^5.6.0: version "5.6.0" resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg== @@ -8930,6 +9441,11 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== +process@^0.11.10: + version "0.11.10" + resolved "https://registry.npmjs.org/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + promise@^8.1.0: version "8.3.0" resolved "https://registry.yarnpkg.com/promise/-/promise-8.3.0.tgz#8cb333d1edeb61ef23869fbb8a4ea0279ab60e0a" @@ -8967,6 +9483,11 @@ proxy-addr@~2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" +proxy-from-env@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" + integrity sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A== + proxy-from-env@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" @@ -8979,6 +9500,14 @@ psl@^1.1.33: dependencies: punycode "^2.3.1" +pump@^3.0.0: + version "3.0.3" + resolved "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz#151d979f1a29668dc0025ec589a455b53282268d" + integrity sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + punycode@^2.1.0, punycode@^2.1.1, punycode@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" @@ -8996,6 +9525,13 @@ qs@6.13.0: dependencies: side-channel "^1.0.6" +qs@6.14.0: + version "6.14.0" + resolved "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz#c63fa40680d2c5c941412a0e899c89af60c0a930" + integrity sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w== + dependencies: + side-channel "^1.1.0" + querystringify@^2.1.1: version "2.2.0" resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" @@ -9526,6 +10062,13 @@ renderkid@^3.0.0: lodash "^4.17.21" strip-ansi "^6.0.1" +request-progress@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz#4ca754081c7fec63f505e4faa825aa06cd669dbe" + integrity sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg== + dependencies: + throttleit "^1.0.0" + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -9597,6 +10140,14 @@ resolve@^2.0.0-next.5: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + restore-cursor@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-5.1.0.tgz#0766d95699efacb14150993f55baf0953ea1ebe7" @@ -9615,7 +10166,7 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.1.0.tgz#0fe13b9522e1473f51b558ee796e08f11f9b489f" integrity sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw== -rfdc@^1.4.1: +rfdc@^1.3.0, rfdc@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.4.1.tgz#778f76c4fb731d93414e8f925fbecf64cce7f6ca" integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== @@ -9651,6 +10202,13 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +rxjs@^7.5.1: + version "7.8.2" + resolved "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz#955bc473ed8af11a002a2be52071bf475638607b" + integrity sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA== + dependencies: + tslib "^2.1.0" + safe-array-concat@^1.1.2, safe-array-concat@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.3.tgz#c9e54ec4f603b0bbb8e7e5007a5ee7aecd1538c3" @@ -9662,7 +10220,7 @@ safe-array-concat@^1.1.2, safe-array-concat@^1.1.3: has-symbols "^1.1.0" isarray "^2.0.5" -safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.1.0, safe-buffer@~5.2.0: +safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -9689,7 +10247,7 @@ safe-regex-test@^1.0.3, safe-regex-test@^1.1.0: es-errors "^1.3.0" is-regex "^1.2.1" -"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -9786,6 +10344,11 @@ semver@^7.3.2, semver@^7.3.5, semver@^7.3.7, semver@^7.5.3, semver@^7.5.4: resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f" integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== +semver@^7.7.1: + version "7.7.2" + resolved "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58" + integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== + send@0.19.0: version "0.19.0" resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" @@ -9982,6 +10545,24 @@ slash@^4.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7" integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew== +slice-ansi@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" + integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + slice-ansi@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-5.0.0.tgz#b73063c57aa96f9cd881654b15294d95d285c42a" @@ -10094,6 +10675,21 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== +sshpk@^1.18.0: + version "1.18.0" + resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz#1663e55cddf4d688b86a46b77f0d5fe363aba028" + integrity sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + stable@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" @@ -10381,7 +10977,7 @@ supports-color@^7.0.0, supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -supports-color@^8.0.0: +supports-color@^8.0.0, supports-color@^8.1.1: version "8.1.1" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== @@ -10571,6 +11167,16 @@ throat@^6.0.1: resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.2.tgz#51a3fbb5e11ae72e2cf74861ed5c8020f89f29fe" integrity sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ== +throttleit@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/throttleit/-/throttleit-1.0.1.tgz#304ec51631c3b770c65c6c6f76938b384000f4d5" + integrity sha512-vDZpf9Chs9mAdfY046mcPt8fg5QSZr37hEH4TXYBnDF+izxgrbRGUAAaBvIk/fJm9aOFCGFd1EsNg5AZCbnQCQ== + +through@^2.3.8: + version "2.3.8" + resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + thunky@^1.0.2: version "1.1.0" resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" @@ -10591,6 +11197,23 @@ tiny-warning@^1.0.2: resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== +tldts-core@^6.1.86: + version "6.1.86" + resolved "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz#a93e6ed9d505cb54c542ce43feb14c73913265d8" + integrity sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA== + +tldts@^6.1.32: + version "6.1.86" + resolved "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz#087e0555b31b9725ee48ca7e77edc56115cd82f7" + integrity sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ== + dependencies: + tldts-core "^6.1.86" + +tmp@~0.2.3: + version "0.2.3" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz#eb783cc22bc1e8bebd0671476d46ea4eb32a79ae" + integrity sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w== + tmpl@1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" @@ -10623,6 +11246,13 @@ tough-cookie@^4.0.0: universalify "^0.2.0" url-parse "^1.5.3" +tough-cookie@^5.0.0: + version "5.1.2" + resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz#66d774b4a1d9e12dc75089725af3ac75ec31bed7" + integrity sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A== + dependencies: + tldts "^6.1.32" + tr46@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" @@ -10644,6 +11274,11 @@ transliteration@^2.3.5: dependencies: yargs "^17.5.1" +tree-kill@1.2.2: + version "1.2.2" + resolved "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" + integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== + tryer@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" @@ -10693,7 +11328,7 @@ tslib@^1.8.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3: +tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== @@ -10705,6 +11340,18 @@ tsutils@^3.21.0: dependencies: tslib "^1.8.1" +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -10884,6 +11531,11 @@ unquote@~1.1.1: resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" integrity sha512-vRCqFv6UhXpWxZPyGDh/F3ZpNv8/qo7w6iufLpQg9aKnQ71qM4B5KiI7Mia9COcjEhrO9LueHpMYjYzsWH3OIg== +untildify@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" + integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== + upath@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" @@ -10976,6 +11628,15 @@ vary@~1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== +verror@1.10.0: + version "1.10.0" + resolved "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw== + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + w3c-hr-time@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" @@ -11450,6 +12111,15 @@ workbox-window@6.6.1: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" @@ -11559,6 +12229,14 @@ yargs@^17.5.1: y18n "^5.0.5" yargs-parser "^21.1.1" +yauzl@^2.10.0: + version "2.10.0" + resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + integrity sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g== + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0" + yn@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"