From d7a5f6cf7b61ac9196ee1b88313ea572d2dfd539 Mon Sep 17 00:00:00 2001 From: Mikhail Deriabin Date: Fri, 24 Jul 2026 15:30:27 +0300 Subject: [PATCH 01/10] try to do bigger change --- .../src/features/AddNewClan2/index.ts | 1 + .../AddNewClan2/model/useNewClanForm.test.ts | 82 +++++++++++++++++ .../AddNewClan2/model/useNewClanForm.ts | 88 ++++++++++++++++++ .../ui/NewClanForm/NewClanForm.module.scss | 4 + .../ui/NewClanForm/NewClanForm.stories.tsx | 12 +++ .../ui/NewClanForm/NewClanForm.tsx | 90 +++++++++++++++++++ .../features/AddNewClan2/validations/index.ts | 38 ++++++++ 7 files changed, 315 insertions(+) create mode 100644 frontend-next-migration/src/features/AddNewClan2/index.ts create mode 100644 frontend-next-migration/src/features/AddNewClan2/model/useNewClanForm.test.ts create mode 100644 frontend-next-migration/src/features/AddNewClan2/model/useNewClanForm.ts create mode 100644 frontend-next-migration/src/features/AddNewClan2/ui/NewClanForm/NewClanForm.module.scss create mode 100644 frontend-next-migration/src/features/AddNewClan2/ui/NewClanForm/NewClanForm.stories.tsx create mode 100644 frontend-next-migration/src/features/AddNewClan2/ui/NewClanForm/NewClanForm.tsx create mode 100644 frontend-next-migration/src/features/AddNewClan2/validations/index.ts diff --git a/frontend-next-migration/src/features/AddNewClan2/index.ts b/frontend-next-migration/src/features/AddNewClan2/index.ts new file mode 100644 index 000000000..715b95233 --- /dev/null +++ b/frontend-next-migration/src/features/AddNewClan2/index.ts @@ -0,0 +1 @@ +export { NewClanForm } from './ui/NewClanForm/NewClanForm'; diff --git a/frontend-next-migration/src/features/AddNewClan2/model/useNewClanForm.test.ts b/frontend-next-migration/src/features/AddNewClan2/model/useNewClanForm.test.ts new file mode 100644 index 000000000..bcfef8313 --- /dev/null +++ b/frontend-next-migration/src/features/AddNewClan2/model/useNewClanForm.test.ts @@ -0,0 +1,82 @@ +import { useForm } from 'react-hook-form'; +import { useCreateClanMutation } from '@/entities/Clan'; +import { act, renderHook } from '@testing-library/react'; +import { useNewClanForm } from './useNewClanForm'; + +jest.mock('react-hook-form', () => ({ + useForm: jest.fn(), +})); + +jest.mock('react-redux', () => ({ + useDispatch: jest.fn(), + useSelector: jest.fn(), +})); + +jest.mock('@hookform/resolvers/yup', () => ({ + yupResolver: jest.fn(), +})); + +jest.mock('@/entities/Clan', () => ({ + useCreateClanMutation: jest.fn(), +})); + +jest.mock('react-toastify', () => ({ + toast: { + success: jest.fn(), + error: jest.fn(), + }, +})); + +describe('onFormSubmit', () => { + const mockCreate = jest.fn(); + const mockOnSuccess = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + (useForm as jest.Mock).mockReturnValue({ + register: jest.fn(), + handleSubmit: jest.fn(), + formState: { errors: {} }, + setValue: jest.fn(), + }); + (useCreateClanMutation as jest.Mock).mockReturnValue([ + mockCreate, + { data: null, isLoading: false, error: null }, + ]); + }); + + it('should check that onSubmitForm correctly convert data for api', async () => { + const { result } = renderHook(() => useNewClanForm({ onSuccess: mockOnSuccess })); + + const mockValues = { + isOpen: true, + name: 'mandoliini', + tag: 'mandoliini', + phrase: 'phrase', + labels: [ + { + label: 'test1', + value: 'TEST1', + }, + { + label: 'test2', + value: 'TEST2', + }, + ], + }; + + const newMockValues = { + isOpen: true, + name: 'mandoliini', + tag: 'mandoliini', + phrase: 'phrase', + labels: ['test1', 'test2'], + }; + + await act(async () => { + await result.current.onFormSubmit(mockValues); + }); + + expect(mockCreate).toHaveBeenCalledWith(newMockValues); + }); +}); diff --git a/frontend-next-migration/src/features/AddNewClan2/model/useNewClanForm.ts b/frontend-next-migration/src/features/AddNewClan2/model/useNewClanForm.ts new file mode 100644 index 000000000..486977274 --- /dev/null +++ b/frontend-next-migration/src/features/AddNewClan2/model/useNewClanForm.ts @@ -0,0 +1,88 @@ +'use client'; +import { yupResolver } from '@hookform/resolvers/yup'; +import { useEffect } from 'react'; +import { FieldValues, useForm } from 'react-hook-form'; +import { useDispatch, useSelector } from 'react-redux'; +import { toast } from 'react-toastify'; +import { IClanCreateDto, useCreateClanMutation } from '@/entities/Clan'; +import { profileActions, selectProfile } from '@/entities/Profile/model/profileSlice/profileSlice'; +import { ValidationAddNewClan } from '../validations'; +import { ProfileSchema } from '@/entities/Profile/types/profile'; + +type Props = { + onSuccess?: () => void; +}; + +export const useNewClanForm = ({ onSuccess }: Props) => { + const { + register, + handleSubmit, + formState: { errors }, + setValue, + } = useForm({ + resolver: yupResolver(ValidationAddNewClan), + }); + + const [ + create, + { + data, + isLoading, + // isError, + error, + }, + ] = useCreateClanMutation(); + + const profile = useSelector((state: ProfileSchema) => selectProfile(state)); + const dispatch = useDispatch(); + + //update store profile after creating new clan + const handleUpdateClanId = (newClanId: string) => { + if (profile) { + const updatedProfile = { + ...profile, + Player: { + ...profile.Player, + clan_id: newClanId, + }, + }; + dispatch(profileActions.setProfile(updatedProfile)); + } else { + console.error('No Profile found in store'); + } + }; + + async function onFormSubmit(fieldValues: FieldValues) { + //converting label to array of lowercase strings + const newFieldValues = { + ...fieldValues, + labels: fieldValues.labels.map((item: any) => item.value.toLowerCase()), + }; + + await create(newFieldValues as IClanCreateDto); + } + + useEffect(() => { + if (data) { + const clanId = data.data.Clan?._id; + handleUpdateClanId(clanId); + toast.success('Klaani oli luotu!'); + onSuccess?.(); + return; + } + + if (error) { + // @ts-ignore todo it works but ts for some reason doesnt recognise the type, figure our why fix + toast.error(error?.data?.message); + return; + } + }, [isLoading, data, error, onSuccess]); + + return { + register, + handleSubmit, + onFormSubmit, + errors, + setValue, + }; +}; diff --git a/frontend-next-migration/src/features/AddNewClan2/ui/NewClanForm/NewClanForm.module.scss b/frontend-next-migration/src/features/AddNewClan2/ui/NewClanForm/NewClanForm.module.scss new file mode 100644 index 000000000..b8f96b9ae --- /dev/null +++ b/frontend-next-migration/src/features/AddNewClan2/ui/NewClanForm/NewClanForm.module.scss @@ -0,0 +1,4 @@ +.Form { + //width: 40%; + //background-color: var(--inverted-bg-color); +} diff --git a/frontend-next-migration/src/features/AddNewClan2/ui/NewClanForm/NewClanForm.stories.tsx b/frontend-next-migration/src/features/AddNewClan2/ui/NewClanForm/NewClanForm.stories.tsx new file mode 100644 index 000000000..abf66b960 --- /dev/null +++ b/frontend-next-migration/src/features/AddNewClan2/ui/NewClanForm/NewClanForm.stories.tsx @@ -0,0 +1,12 @@ +import { StoryObj, Meta } from '@storybook/nextjs'; +import { NewClanForm } from './NewClanForm'; + +export default { + title: 'features/NewClanForm', + component: NewClanForm, + args: { + className: '', + }, +} as Meta; + +export const Default: StoryObj = {}; diff --git a/frontend-next-migration/src/features/AddNewClan2/ui/NewClanForm/NewClanForm.tsx b/frontend-next-migration/src/features/AddNewClan2/ui/NewClanForm/NewClanForm.tsx new file mode 100644 index 000000000..8ec96f7cc --- /dev/null +++ b/frontend-next-migration/src/features/AddNewClan2/ui/NewClanForm/NewClanForm.tsx @@ -0,0 +1,90 @@ +'use client'; +import { CustomForm } from '@/shared/ui/CustomForm'; +import { classNames } from '@/shared/lib/classNames/classNames'; +import { useNewClanForm } from '../../model/useNewClanForm'; +import cls from './NewClanForm.module.scss'; +import { ClanLabel } from '@/entities/Clan/enum/clanLabel.enum'; +import { useState } from 'react'; + +type Props = { + onSuccess?: () => void; + className?: string; +}; + +export const NewClanForm = ({ onSuccess, className = '' }: Props) => { + const { register, handleSubmit, onFormSubmit, errors, setValue } = useNewClanForm({ + onSuccess, + }); + + const [selected, setSelected] = useState<{ label: any; value: string }[]>([]); + + return ( + + Luo Klaani. Changed + + + + + + + + { + setSelected(newSelection); + setValue('labels', newSelection); + }} + /> + + { + + } + + Vahvista + + ); +}; diff --git a/frontend-next-migration/src/features/AddNewClan2/validations/index.ts b/frontend-next-migration/src/features/AddNewClan2/validations/index.ts new file mode 100644 index 000000000..ba2cd1d33 --- /dev/null +++ b/frontend-next-migration/src/features/AddNewClan2/validations/index.ts @@ -0,0 +1,38 @@ +import * as yup from 'yup'; + +//todo add i18n +export const ValidationAddNewClan = yup.object().shape({ + name: yup + .string() + .required('Vaadittu') + .min(3, 'Klaanin nimen on oltava vähintään 3 merkkiä pitkä') + .max(15, 'Klaanin nimen on oltava enintään 15 merkkiä pitkä') + .matches(/^[A-Za-z]+$/, 'Klaanin nimi saa sisältää vain kirjaimia'), + + tag: yup + .string() + .required('Tagi on vaadittu') + .min(3, 'Tagin on oltava vähintään 3 merkkiä pitkä') + .max(10, 'Tagin on oltava enintään 10 merkkiä pitkä') + .matches(/^[A-Za-z0-9_]+$/, 'Tagi voi sisältää vain kirjaimia, numeroita ja alaviivoja'), + + phrase: yup + .string() + .required() + .min(3, 'Moton on oltava vähintään 3 merkkiä pitkä') + .max(30, 'Moton on oltava enintään 30 merkkiä pitkä') + .matches(/^[A-Za-z0-9_]+$/, 'Motto voi sisältää vain kirjaimia, numeroita ja alaviivoja'), + + labels: yup + .array() + .of( + yup.object({ + label: yup.string(), + value: yup.string(), + }), + ) + .required() + .min(1, 'Valitse vähintään 1'), + + isOpen: yup.boolean(), +}); From 141abdfbfcd63df0b1b81fdccb0fb0f63ce4eadf Mon Sep 17 00:00:00 2001 From: Mikhail Deriabin Date: Fri, 24 Jul 2026 15:31:18 +0300 Subject: [PATCH 02/10] add new branch to ci --- .github/workflows/ci-cd.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index f19f09cab..f1eda6e33 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -6,6 +6,7 @@ on: - main - dev - MikhailDeriabin/feature/670-migrate-ci-gh-actions + - MikhailDeriabin/feature/670-migrate-ci-gh-actions-new # pull_request: # branches: # - '**' From f52e05d6d3e29fbce8c8c263f3ea21ae865ed88c Mon Sep 17 00:00:00 2001 From: Mikhail Deriabin Date: Fri, 24 Jul 2026 15:40:24 +0300 Subject: [PATCH 03/10] add PR checks --- .github/workflows/ci-cd.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index f1eda6e33..870481c9b 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -7,9 +7,9 @@ on: - dev - MikhailDeriabin/feature/670-migrate-ci-gh-actions - MikhailDeriabin/feature/670-migrate-ci-gh-actions-new -# pull_request: -# branches: -# - '**' + pull_request: + branches: + - '**' defaults: run: @@ -18,7 +18,7 @@ defaults: jobs: test: name: Run tests - runs-on: [ self-hosted, gh-runner-common ] + runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v7 From da1e300ff0c6698646c4b38393444225efb746a9 Mon Sep 17 00:00:00 2001 From: Mikhail Deriabin Date: Fri, 24 Jul 2026 15:45:07 +0300 Subject: [PATCH 04/10] archive old ci file --- .../{workflows/ci.yml => deprecated/ci-archived-24-07-2026.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{workflows/ci.yml => deprecated/ci-archived-24-07-2026.yml} (100%) diff --git a/.github/workflows/ci.yml b/.github/deprecated/ci-archived-24-07-2026.yml similarity index 100% rename from .github/workflows/ci.yml rename to .github/deprecated/ci-archived-24-07-2026.yml From b7c569214dfe2c2f5f38c26293994389639b1619 Mon Sep 17 00:00:00 2001 From: Mikhail Deriabin Date: Fri, 24 Jul 2026 15:49:19 +0300 Subject: [PATCH 05/10] add codecov config --- frontend-next-migration/codecov.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 frontend-next-migration/codecov.yml diff --git a/frontend-next-migration/codecov.yml b/frontend-next-migration/codecov.yml new file mode 100644 index 000000000..fe59e4ea1 --- /dev/null +++ b/frontend-next-migration/codecov.yml @@ -0,0 +1,11 @@ +coverage: + status: + project: + default: + target: 90 + patch: + default: + target: 90 + +codecov: + branch: dev \ No newline at end of file From 0190f3ec4f3cfca5c77b8a717a940b970c5799c8 Mon Sep 17 00:00:00 2001 From: Mikhail Deriabin Date: Fri, 24 Jul 2026 15:59:44 +0300 Subject: [PATCH 06/10] move codecov to root --- .../deprecated/Jenkinsfile-archived-24-07-2026 | 0 .github/workflows/ci-cd.yml | 3 ++- frontend-next-migration/codecov.yml => codecov.yml | 0 3 files changed, 2 insertions(+), 1 deletion(-) rename Jenkinsfile => .github/deprecated/Jenkinsfile-archived-24-07-2026 (100%) rename frontend-next-migration/codecov.yml => codecov.yml (100%) diff --git a/Jenkinsfile b/.github/deprecated/Jenkinsfile-archived-24-07-2026 similarity index 100% rename from Jenkinsfile rename to .github/deprecated/Jenkinsfile-archived-24-07-2026 diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 870481c9b..fd0a053b5 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -18,7 +18,8 @@ defaults: jobs: test: name: Run tests - runs-on: ubuntu-latest + runs-on: [self-hosted, gh-runner-common] +# runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v7 diff --git a/frontend-next-migration/codecov.yml b/codecov.yml similarity index 100% rename from frontend-next-migration/codecov.yml rename to codecov.yml From d4ee91e677831a42d62fc394cd1afb74005a8287 Mon Sep 17 00:00:00 2001 From: Mikhail Deriabin Date: Fri, 24 Jul 2026 16:02:18 +0300 Subject: [PATCH 07/10] lower coverage target --- codecov.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codecov.yml b/codecov.yml index fe59e4ea1..9f3ea4b6e 100644 --- a/codecov.yml +++ b/codecov.yml @@ -2,10 +2,10 @@ coverage: status: project: default: - target: 90 + target: 1 patch: default: - target: 90 + target: 1 codecov: branch: dev \ No newline at end of file From 4139e2c1038b4385d58382ac011bf193af4154fc Mon Sep 17 00:00:00 2001 From: Mikhail Deriabin Date: Fri, 24 Jul 2026 16:06:24 +0300 Subject: [PATCH 08/10] add coverage badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ca2806556..1530477d2 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +[![codecov](https://yrfbcpxonsco.mikhail.com.de/github/Alt-Org/Altzone-WebPages/graph/badge.svg?token=HYZVADVM8S)](https://yrfbcpxonsco.mikhail.com.de/github/Alt-Org/Altzone-WebPages) + # Altzone-WebPages Welcome to the **Altzone-WebPages** repository! 🎉 From d118d687deee07738875f2ee3d26dd098b8b7d66 Mon Sep 17 00:00:00 2001 From: Mikhail Deriabin Date: Fri, 24 Jul 2026 16:09:43 +0300 Subject: [PATCH 09/10] remove files used in ci speed tests --- .../AddNewClan/ui/NewClanForm/NewClanForm.tsx | 2 +- .../src/features/AddNewClan1/index.ts | 1 - .../AddNewClan1/model/useNewClanForm.test.ts | 82 ----------------- .../AddNewClan1/model/useNewClanForm.ts | 88 ------------------ .../ui/NewClanForm/NewClanForm.module.scss | 4 - .../ui/NewClanForm/NewClanForm.stories.tsx | 12 --- .../ui/NewClanForm/NewClanForm.tsx | 90 ------------------- .../features/AddNewClan1/validations/index.ts | 38 -------- .../src/features/AddNewClan2/index.ts | 1 - .../AddNewClan2/model/useNewClanForm.test.ts | 82 ----------------- .../AddNewClan2/model/useNewClanForm.ts | 88 ------------------ .../ui/NewClanForm/NewClanForm.module.scss | 4 - .../ui/NewClanForm/NewClanForm.stories.tsx | 12 --- .../ui/NewClanForm/NewClanForm.tsx | 90 ------------------- .../features/AddNewClan2/validations/index.ts | 38 -------- 15 files changed, 1 insertion(+), 631 deletions(-) delete mode 100644 frontend-next-migration/src/features/AddNewClan1/index.ts delete mode 100644 frontend-next-migration/src/features/AddNewClan1/model/useNewClanForm.test.ts delete mode 100644 frontend-next-migration/src/features/AddNewClan1/model/useNewClanForm.ts delete mode 100644 frontend-next-migration/src/features/AddNewClan1/ui/NewClanForm/NewClanForm.module.scss delete mode 100644 frontend-next-migration/src/features/AddNewClan1/ui/NewClanForm/NewClanForm.stories.tsx delete mode 100644 frontend-next-migration/src/features/AddNewClan1/ui/NewClanForm/NewClanForm.tsx delete mode 100644 frontend-next-migration/src/features/AddNewClan1/validations/index.ts delete mode 100644 frontend-next-migration/src/features/AddNewClan2/index.ts delete mode 100644 frontend-next-migration/src/features/AddNewClan2/model/useNewClanForm.test.ts delete mode 100644 frontend-next-migration/src/features/AddNewClan2/model/useNewClanForm.ts delete mode 100644 frontend-next-migration/src/features/AddNewClan2/ui/NewClanForm/NewClanForm.module.scss delete mode 100644 frontend-next-migration/src/features/AddNewClan2/ui/NewClanForm/NewClanForm.stories.tsx delete mode 100644 frontend-next-migration/src/features/AddNewClan2/ui/NewClanForm/NewClanForm.tsx delete mode 100644 frontend-next-migration/src/features/AddNewClan2/validations/index.ts diff --git a/frontend-next-migration/src/features/AddNewClan/ui/NewClanForm/NewClanForm.tsx b/frontend-next-migration/src/features/AddNewClan/ui/NewClanForm/NewClanForm.tsx index 8ec96f7cc..56f42d4a7 100644 --- a/frontend-next-migration/src/features/AddNewClan/ui/NewClanForm/NewClanForm.tsx +++ b/frontend-next-migration/src/features/AddNewClan/ui/NewClanForm/NewClanForm.tsx @@ -23,7 +23,7 @@ export const NewClanForm = ({ onSuccess, className = '' }: Props) => { className={classNames(cls.Form, {}, [className])} onSubmit={handleSubmit(onFormSubmit)} > - Luo Klaani. Changed + Luo Klaani ({ - useForm: jest.fn(), -})); - -jest.mock('react-redux', () => ({ - useDispatch: jest.fn(), - useSelector: jest.fn(), -})); - -jest.mock('@hookform/resolvers/yup', () => ({ - yupResolver: jest.fn(), -})); - -jest.mock('@/entities/Clan', () => ({ - useCreateClanMutation: jest.fn(), -})); - -jest.mock('react-toastify', () => ({ - toast: { - success: jest.fn(), - error: jest.fn(), - }, -})); - -describe('onFormSubmit', () => { - const mockCreate = jest.fn(); - const mockOnSuccess = jest.fn(); - - beforeEach(() => { - jest.clearAllMocks(); - (useForm as jest.Mock).mockReturnValue({ - register: jest.fn(), - handleSubmit: jest.fn(), - formState: { errors: {} }, - setValue: jest.fn(), - }); - (useCreateClanMutation as jest.Mock).mockReturnValue([ - mockCreate, - { data: null, isLoading: false, error: null }, - ]); - }); - - it('should check that onSubmitForm correctly convert data for api', async () => { - const { result } = renderHook(() => useNewClanForm({ onSuccess: mockOnSuccess })); - - const mockValues = { - isOpen: true, - name: 'mandoliini', - tag: 'mandoliini', - phrase: 'phrase', - labels: [ - { - label: 'test1', - value: 'TEST1', - }, - { - label: 'test2', - value: 'TEST2', - }, - ], - }; - - const newMockValues = { - isOpen: true, - name: 'mandoliini', - tag: 'mandoliini', - phrase: 'phrase', - labels: ['test1', 'test2'], - }; - - await act(async () => { - await result.current.onFormSubmit(mockValues); - }); - - expect(mockCreate).toHaveBeenCalledWith(newMockValues); - }); -}); diff --git a/frontend-next-migration/src/features/AddNewClan1/model/useNewClanForm.ts b/frontend-next-migration/src/features/AddNewClan1/model/useNewClanForm.ts deleted file mode 100644 index 486977274..000000000 --- a/frontend-next-migration/src/features/AddNewClan1/model/useNewClanForm.ts +++ /dev/null @@ -1,88 +0,0 @@ -'use client'; -import { yupResolver } from '@hookform/resolvers/yup'; -import { useEffect } from 'react'; -import { FieldValues, useForm } from 'react-hook-form'; -import { useDispatch, useSelector } from 'react-redux'; -import { toast } from 'react-toastify'; -import { IClanCreateDto, useCreateClanMutation } from '@/entities/Clan'; -import { profileActions, selectProfile } from '@/entities/Profile/model/profileSlice/profileSlice'; -import { ValidationAddNewClan } from '../validations'; -import { ProfileSchema } from '@/entities/Profile/types/profile'; - -type Props = { - onSuccess?: () => void; -}; - -export const useNewClanForm = ({ onSuccess }: Props) => { - const { - register, - handleSubmit, - formState: { errors }, - setValue, - } = useForm({ - resolver: yupResolver(ValidationAddNewClan), - }); - - const [ - create, - { - data, - isLoading, - // isError, - error, - }, - ] = useCreateClanMutation(); - - const profile = useSelector((state: ProfileSchema) => selectProfile(state)); - const dispatch = useDispatch(); - - //update store profile after creating new clan - const handleUpdateClanId = (newClanId: string) => { - if (profile) { - const updatedProfile = { - ...profile, - Player: { - ...profile.Player, - clan_id: newClanId, - }, - }; - dispatch(profileActions.setProfile(updatedProfile)); - } else { - console.error('No Profile found in store'); - } - }; - - async function onFormSubmit(fieldValues: FieldValues) { - //converting label to array of lowercase strings - const newFieldValues = { - ...fieldValues, - labels: fieldValues.labels.map((item: any) => item.value.toLowerCase()), - }; - - await create(newFieldValues as IClanCreateDto); - } - - useEffect(() => { - if (data) { - const clanId = data.data.Clan?._id; - handleUpdateClanId(clanId); - toast.success('Klaani oli luotu!'); - onSuccess?.(); - return; - } - - if (error) { - // @ts-ignore todo it works but ts for some reason doesnt recognise the type, figure our why fix - toast.error(error?.data?.message); - return; - } - }, [isLoading, data, error, onSuccess]); - - return { - register, - handleSubmit, - onFormSubmit, - errors, - setValue, - }; -}; diff --git a/frontend-next-migration/src/features/AddNewClan1/ui/NewClanForm/NewClanForm.module.scss b/frontend-next-migration/src/features/AddNewClan1/ui/NewClanForm/NewClanForm.module.scss deleted file mode 100644 index b8f96b9ae..000000000 --- a/frontend-next-migration/src/features/AddNewClan1/ui/NewClanForm/NewClanForm.module.scss +++ /dev/null @@ -1,4 +0,0 @@ -.Form { - //width: 40%; - //background-color: var(--inverted-bg-color); -} diff --git a/frontend-next-migration/src/features/AddNewClan1/ui/NewClanForm/NewClanForm.stories.tsx b/frontend-next-migration/src/features/AddNewClan1/ui/NewClanForm/NewClanForm.stories.tsx deleted file mode 100644 index abf66b960..000000000 --- a/frontend-next-migration/src/features/AddNewClan1/ui/NewClanForm/NewClanForm.stories.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { StoryObj, Meta } from '@storybook/nextjs'; -import { NewClanForm } from './NewClanForm'; - -export default { - title: 'features/NewClanForm', - component: NewClanForm, - args: { - className: '', - }, -} as Meta; - -export const Default: StoryObj = {}; diff --git a/frontend-next-migration/src/features/AddNewClan1/ui/NewClanForm/NewClanForm.tsx b/frontend-next-migration/src/features/AddNewClan1/ui/NewClanForm/NewClanForm.tsx deleted file mode 100644 index 8ec96f7cc..000000000 --- a/frontend-next-migration/src/features/AddNewClan1/ui/NewClanForm/NewClanForm.tsx +++ /dev/null @@ -1,90 +0,0 @@ -'use client'; -import { CustomForm } from '@/shared/ui/CustomForm'; -import { classNames } from '@/shared/lib/classNames/classNames'; -import { useNewClanForm } from '../../model/useNewClanForm'; -import cls from './NewClanForm.module.scss'; -import { ClanLabel } from '@/entities/Clan/enum/clanLabel.enum'; -import { useState } from 'react'; - -type Props = { - onSuccess?: () => void; - className?: string; -}; - -export const NewClanForm = ({ onSuccess, className = '' }: Props) => { - const { register, handleSubmit, onFormSubmit, errors, setValue } = useNewClanForm({ - onSuccess, - }); - - const [selected, setSelected] = useState<{ label: any; value: string }[]>([]); - - return ( - - Luo Klaani. Changed - - - - - - - - { - setSelected(newSelection); - setValue('labels', newSelection); - }} - /> - - { - - } - - Vahvista - - ); -}; diff --git a/frontend-next-migration/src/features/AddNewClan1/validations/index.ts b/frontend-next-migration/src/features/AddNewClan1/validations/index.ts deleted file mode 100644 index ba2cd1d33..000000000 --- a/frontend-next-migration/src/features/AddNewClan1/validations/index.ts +++ /dev/null @@ -1,38 +0,0 @@ -import * as yup from 'yup'; - -//todo add i18n -export const ValidationAddNewClan = yup.object().shape({ - name: yup - .string() - .required('Vaadittu') - .min(3, 'Klaanin nimen on oltava vähintään 3 merkkiä pitkä') - .max(15, 'Klaanin nimen on oltava enintään 15 merkkiä pitkä') - .matches(/^[A-Za-z]+$/, 'Klaanin nimi saa sisältää vain kirjaimia'), - - tag: yup - .string() - .required('Tagi on vaadittu') - .min(3, 'Tagin on oltava vähintään 3 merkkiä pitkä') - .max(10, 'Tagin on oltava enintään 10 merkkiä pitkä') - .matches(/^[A-Za-z0-9_]+$/, 'Tagi voi sisältää vain kirjaimia, numeroita ja alaviivoja'), - - phrase: yup - .string() - .required() - .min(3, 'Moton on oltava vähintään 3 merkkiä pitkä') - .max(30, 'Moton on oltava enintään 30 merkkiä pitkä') - .matches(/^[A-Za-z0-9_]+$/, 'Motto voi sisältää vain kirjaimia, numeroita ja alaviivoja'), - - labels: yup - .array() - .of( - yup.object({ - label: yup.string(), - value: yup.string(), - }), - ) - .required() - .min(1, 'Valitse vähintään 1'), - - isOpen: yup.boolean(), -}); diff --git a/frontend-next-migration/src/features/AddNewClan2/index.ts b/frontend-next-migration/src/features/AddNewClan2/index.ts deleted file mode 100644 index 715b95233..000000000 --- a/frontend-next-migration/src/features/AddNewClan2/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { NewClanForm } from './ui/NewClanForm/NewClanForm'; diff --git a/frontend-next-migration/src/features/AddNewClan2/model/useNewClanForm.test.ts b/frontend-next-migration/src/features/AddNewClan2/model/useNewClanForm.test.ts deleted file mode 100644 index bcfef8313..000000000 --- a/frontend-next-migration/src/features/AddNewClan2/model/useNewClanForm.test.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { useForm } from 'react-hook-form'; -import { useCreateClanMutation } from '@/entities/Clan'; -import { act, renderHook } from '@testing-library/react'; -import { useNewClanForm } from './useNewClanForm'; - -jest.mock('react-hook-form', () => ({ - useForm: jest.fn(), -})); - -jest.mock('react-redux', () => ({ - useDispatch: jest.fn(), - useSelector: jest.fn(), -})); - -jest.mock('@hookform/resolvers/yup', () => ({ - yupResolver: jest.fn(), -})); - -jest.mock('@/entities/Clan', () => ({ - useCreateClanMutation: jest.fn(), -})); - -jest.mock('react-toastify', () => ({ - toast: { - success: jest.fn(), - error: jest.fn(), - }, -})); - -describe('onFormSubmit', () => { - const mockCreate = jest.fn(); - const mockOnSuccess = jest.fn(); - - beforeEach(() => { - jest.clearAllMocks(); - (useForm as jest.Mock).mockReturnValue({ - register: jest.fn(), - handleSubmit: jest.fn(), - formState: { errors: {} }, - setValue: jest.fn(), - }); - (useCreateClanMutation as jest.Mock).mockReturnValue([ - mockCreate, - { data: null, isLoading: false, error: null }, - ]); - }); - - it('should check that onSubmitForm correctly convert data for api', async () => { - const { result } = renderHook(() => useNewClanForm({ onSuccess: mockOnSuccess })); - - const mockValues = { - isOpen: true, - name: 'mandoliini', - tag: 'mandoliini', - phrase: 'phrase', - labels: [ - { - label: 'test1', - value: 'TEST1', - }, - { - label: 'test2', - value: 'TEST2', - }, - ], - }; - - const newMockValues = { - isOpen: true, - name: 'mandoliini', - tag: 'mandoliini', - phrase: 'phrase', - labels: ['test1', 'test2'], - }; - - await act(async () => { - await result.current.onFormSubmit(mockValues); - }); - - expect(mockCreate).toHaveBeenCalledWith(newMockValues); - }); -}); diff --git a/frontend-next-migration/src/features/AddNewClan2/model/useNewClanForm.ts b/frontend-next-migration/src/features/AddNewClan2/model/useNewClanForm.ts deleted file mode 100644 index 486977274..000000000 --- a/frontend-next-migration/src/features/AddNewClan2/model/useNewClanForm.ts +++ /dev/null @@ -1,88 +0,0 @@ -'use client'; -import { yupResolver } from '@hookform/resolvers/yup'; -import { useEffect } from 'react'; -import { FieldValues, useForm } from 'react-hook-form'; -import { useDispatch, useSelector } from 'react-redux'; -import { toast } from 'react-toastify'; -import { IClanCreateDto, useCreateClanMutation } from '@/entities/Clan'; -import { profileActions, selectProfile } from '@/entities/Profile/model/profileSlice/profileSlice'; -import { ValidationAddNewClan } from '../validations'; -import { ProfileSchema } from '@/entities/Profile/types/profile'; - -type Props = { - onSuccess?: () => void; -}; - -export const useNewClanForm = ({ onSuccess }: Props) => { - const { - register, - handleSubmit, - formState: { errors }, - setValue, - } = useForm({ - resolver: yupResolver(ValidationAddNewClan), - }); - - const [ - create, - { - data, - isLoading, - // isError, - error, - }, - ] = useCreateClanMutation(); - - const profile = useSelector((state: ProfileSchema) => selectProfile(state)); - const dispatch = useDispatch(); - - //update store profile after creating new clan - const handleUpdateClanId = (newClanId: string) => { - if (profile) { - const updatedProfile = { - ...profile, - Player: { - ...profile.Player, - clan_id: newClanId, - }, - }; - dispatch(profileActions.setProfile(updatedProfile)); - } else { - console.error('No Profile found in store'); - } - }; - - async function onFormSubmit(fieldValues: FieldValues) { - //converting label to array of lowercase strings - const newFieldValues = { - ...fieldValues, - labels: fieldValues.labels.map((item: any) => item.value.toLowerCase()), - }; - - await create(newFieldValues as IClanCreateDto); - } - - useEffect(() => { - if (data) { - const clanId = data.data.Clan?._id; - handleUpdateClanId(clanId); - toast.success('Klaani oli luotu!'); - onSuccess?.(); - return; - } - - if (error) { - // @ts-ignore todo it works but ts for some reason doesnt recognise the type, figure our why fix - toast.error(error?.data?.message); - return; - } - }, [isLoading, data, error, onSuccess]); - - return { - register, - handleSubmit, - onFormSubmit, - errors, - setValue, - }; -}; diff --git a/frontend-next-migration/src/features/AddNewClan2/ui/NewClanForm/NewClanForm.module.scss b/frontend-next-migration/src/features/AddNewClan2/ui/NewClanForm/NewClanForm.module.scss deleted file mode 100644 index b8f96b9ae..000000000 --- a/frontend-next-migration/src/features/AddNewClan2/ui/NewClanForm/NewClanForm.module.scss +++ /dev/null @@ -1,4 +0,0 @@ -.Form { - //width: 40%; - //background-color: var(--inverted-bg-color); -} diff --git a/frontend-next-migration/src/features/AddNewClan2/ui/NewClanForm/NewClanForm.stories.tsx b/frontend-next-migration/src/features/AddNewClan2/ui/NewClanForm/NewClanForm.stories.tsx deleted file mode 100644 index abf66b960..000000000 --- a/frontend-next-migration/src/features/AddNewClan2/ui/NewClanForm/NewClanForm.stories.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { StoryObj, Meta } from '@storybook/nextjs'; -import { NewClanForm } from './NewClanForm'; - -export default { - title: 'features/NewClanForm', - component: NewClanForm, - args: { - className: '', - }, -} as Meta; - -export const Default: StoryObj = {}; diff --git a/frontend-next-migration/src/features/AddNewClan2/ui/NewClanForm/NewClanForm.tsx b/frontend-next-migration/src/features/AddNewClan2/ui/NewClanForm/NewClanForm.tsx deleted file mode 100644 index 8ec96f7cc..000000000 --- a/frontend-next-migration/src/features/AddNewClan2/ui/NewClanForm/NewClanForm.tsx +++ /dev/null @@ -1,90 +0,0 @@ -'use client'; -import { CustomForm } from '@/shared/ui/CustomForm'; -import { classNames } from '@/shared/lib/classNames/classNames'; -import { useNewClanForm } from '../../model/useNewClanForm'; -import cls from './NewClanForm.module.scss'; -import { ClanLabel } from '@/entities/Clan/enum/clanLabel.enum'; -import { useState } from 'react'; - -type Props = { - onSuccess?: () => void; - className?: string; -}; - -export const NewClanForm = ({ onSuccess, className = '' }: Props) => { - const { register, handleSubmit, onFormSubmit, errors, setValue } = useNewClanForm({ - onSuccess, - }); - - const [selected, setSelected] = useState<{ label: any; value: string }[]>([]); - - return ( - - Luo Klaani. Changed - - - - - - - - { - setSelected(newSelection); - setValue('labels', newSelection); - }} - /> - - { - - } - - Vahvista - - ); -}; diff --git a/frontend-next-migration/src/features/AddNewClan2/validations/index.ts b/frontend-next-migration/src/features/AddNewClan2/validations/index.ts deleted file mode 100644 index ba2cd1d33..000000000 --- a/frontend-next-migration/src/features/AddNewClan2/validations/index.ts +++ /dev/null @@ -1,38 +0,0 @@ -import * as yup from 'yup'; - -//todo add i18n -export const ValidationAddNewClan = yup.object().shape({ - name: yup - .string() - .required('Vaadittu') - .min(3, 'Klaanin nimen on oltava vähintään 3 merkkiä pitkä') - .max(15, 'Klaanin nimen on oltava enintään 15 merkkiä pitkä') - .matches(/^[A-Za-z]+$/, 'Klaanin nimi saa sisältää vain kirjaimia'), - - tag: yup - .string() - .required('Tagi on vaadittu') - .min(3, 'Tagin on oltava vähintään 3 merkkiä pitkä') - .max(10, 'Tagin on oltava enintään 10 merkkiä pitkä') - .matches(/^[A-Za-z0-9_]+$/, 'Tagi voi sisältää vain kirjaimia, numeroita ja alaviivoja'), - - phrase: yup - .string() - .required() - .min(3, 'Moton on oltava vähintään 3 merkkiä pitkä') - .max(30, 'Moton on oltava enintään 30 merkkiä pitkä') - .matches(/^[A-Za-z0-9_]+$/, 'Motto voi sisältää vain kirjaimia, numeroita ja alaviivoja'), - - labels: yup - .array() - .of( - yup.object({ - label: yup.string(), - value: yup.string(), - }), - ) - .required() - .min(1, 'Valitse vähintään 1'), - - isOpen: yup.boolean(), -}); From 57853aa2bf34fe79afc168aabbc03e4dc8199eee Mon Sep 17 00:00:00 2001 From: Mikhail Deriabin Date: Fri, 24 Jul 2026 16:16:00 +0300 Subject: [PATCH 10/10] test whole ci --- .github/workflows/ci-cd.yml | 189 +++++++++--------- .../src/preparedPages/AboutPage/ui/About.tsx | 2 +- 2 files changed, 96 insertions(+), 95 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index fd0a053b5..990f0dc4d 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -18,8 +18,8 @@ defaults: jobs: test: name: Run tests - runs-on: [self-hosted, gh-runner-common] -# runs-on: ubuntu-latest +# runs-on: [self-hosted, gh-runner-common] + runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v7 @@ -64,96 +64,97 @@ jobs: files: ./frontend-next-migration/coverage/coverage-final.json fail_ci_if_error: true -# build-and-push: -# name: Build and Push Docker Image -## needs: test -# if: github.ref_name == 'main' || github.ref_name == 'dev' || github.ref_name == 'MikhailDeriabin/feature/670-migrate-ci-gh-actions' -# runs-on: [self-hosted, gh-runner-common] -# steps: -# - name: Checkout code -# uses: actions/checkout@v7 -# -# - name: Log in to Docker Hub -# uses: docker/login-action@v4 -# with: -# username: ${{ secrets.DOCKERHUB_USERNAME }} -# password: ${{ secrets.DOCKERHUB_TOKEN }} -# -# - name: Write build env file -# env: -# ENV_LOCAL_BUILD: ${{ secrets.SITE_ENV_LOCAL_BUILD }} -# run: printf '%s' "$ENV_LOCAL_BUILD" > .env.local -# -# - name: Build and push image -# uses: docker/build-push-action@v7 -# env: -# DOCKER_BUILD_RECORD_UPLOAD: false -# with: -# context: frontend-next-migration -# push: true -# load: true -# tags: | -# ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:dev-27 -# ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:dev-latest -## ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:${{ github.ref_name }}-${{ github.run_number }} -## ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:${{ github.ref_name }}-latest -# -# - name: Clean up build env file -# if: always() -# run: rm -f .env.local -# -# - name: Scan image for vulnerabilities -# uses: aquasecurity/trivy-action@v0.36.0 -# with: -# image-ref: ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:dev-27 -## image-ref: ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:${{ github.ref_name }}-${{ github.run_number }} -# format: json -# ignore-unfixed: true -# exit-code: '0' -# output: frontend-next-migration/trivy-results.json -# -# - name: Upload vulnerabilities to summary tab -# if: always() -# run: | -# { -# echo "## Vulnerability scan results" -# echo "" -# echo "| Target | Package | CVE | Severity | Installed | Fixed |" -# echo "|---|---|---|---|---|---|" -# jq -r ' -# .Results[]? -# | select(.Vulnerabilities != null) -# | .Target as $t -# | .Vulnerabilities[] -# | "| \($t) | \(.PkgName) | \(.VulnerabilityID) | \(.Severity) | \(.InstalledVersion) | \(.FixedVersion // "-") |" -# ' trivy-results.json -# } >> "$GITHUB_STEP_SUMMARY" -# -# - name: Convert scan results to SARIF format -# if: always() -# run: trivy convert --format sarif --output trivy-results.sarif trivy-results.json -# -# - name: Upload vulnerabilities to Security tab -# uses: github/codeql-action/upload-sarif@v4 -# with: -# sarif_file: frontend-next-migration/trivy-results.sarif - -# notify: -# name: Notify server about new image build -# needs: build-and-push -# if: github.ref_name == 'main' || github.ref_name == 'dev' -# runs-on: [self-hosted, gh-runner-common] -# steps: -# - name: Notify server -# env: -# WEBHOOK_SECRET: ${{ secrets.SERVER_WEBHOOK_NOTIFY_SECRET }} -# WEBHOOK_URL: ${{ secrets.SERVER_WEBHOOK_NOTIFY_URL }} + build-and-push: + name: Build and Push Docker Image + needs: test + if: github.ref_name == 'main' || github.ref_name == 'dev' || github.ref_name == 'MikhailDeriabin/feature/670-migrate-ci-gh-actions' + runs-on: [self-hosted, gh-runner-common] + steps: + - name: Checkout code + uses: actions/checkout@v7 + + - name: Log in to Docker Hub + uses: docker/login-action@v4 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Write build env file + env: + ENV_LOCAL_BUILD: ${{ secrets.SITE_ENV_LOCAL_BUILD }} + run: printf '%s' "$ENV_LOCAL_BUILD" > .env.local + + - name: Build and push image + uses: docker/build-push-action@v7 + env: + DOCKER_BUILD_RECORD_UPLOAD: false + with: + context: frontend-next-migration + push: true + load: true + tags: | + ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:dev-${{ github.run_number }} + ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:dev-latest +# ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:${{ github.ref_name }}-${{ github.run_number }} +# ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:${{ github.ref_name }}-latest + + - name: Clean up build env file + if: always() + run: rm -f .env.local + + - name: Scan image for vulnerabilities + uses: aquasecurity/trivy-action@v0.36.0 + with: + image-ref: ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:dev-${{ github.run_number }} +# image-ref: ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_REPO }}:${{ github.ref_name }}-${{ github.run_number }} + format: json + ignore-unfixed: true + exit-code: '0' + output: frontend-next-migration/trivy-results.json + + - name: Upload vulnerabilities to summary tab + if: always() + run: | + { + echo "## Vulnerability scan results" + echo "" + echo "| Target | Package | CVE | Severity | Installed | Fixed |" + echo "|---|---|---|---|---|---|" + jq -r ' + .Results[]? + | select(.Vulnerabilities != null) + | .Target as $t + | .Vulnerabilities[] + | "| \($t) | \(.PkgName) | \(.VulnerabilityID) | \(.Severity) | \(.InstalledVersion) | \(.FixedVersion // "-") |" + ' trivy-results.json + } >> "$GITHUB_STEP_SUMMARY" + + - name: Convert scan results to SARIF format + if: always() + run: trivy convert --format sarif --output trivy-results.sarif trivy-results.json + + - name: Upload vulnerabilities to Security tab + uses: github/codeql-action/upload-sarif@v4 + with: + sarif_file: frontend-next-migration/trivy-results.sarif + + notify: + name: Notify server about new image build + needs: build-and-push + if: github.ref_name == 'main' || github.ref_name == 'dev' || github.ref_name == 'MikhailDeriabin/feature/670-migrate-ci-gh-actions' + runs-on: [self-hosted, gh-runner-common] + steps: + - name: Notify server + env: + WEBHOOK_SECRET: ${{ secrets.SERVER_WEBHOOK_NOTIFY_SECRET }} + WEBHOOK_URL: ${{ secrets.SERVER_WEBHOOK_NOTIFY_URL }} + PAYLOAD: '{"name": "site", "tag": "dev"}' # PAYLOAD: '{"name": "site", "tag": "${{ github.ref_name }}"}' -# run: | -# SIGNATURE=$(echo "$PAYLOAD" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" | sed 's/^.* //') -# -# curl -s -o /dev/null -X POST "$WEBHOOK_URL" \ -# -H "Content-Type: application/json" \ -# -H "X-Hub-Signature: sha256=$SIGNATURE" \ -# -d "$PAYLOAD" \ -# --insecure \ No newline at end of file + run: | + SIGNATURE=$(echo "$PAYLOAD" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" | sed 's/^.* //') + + curl -s -o /dev/null -X POST "$WEBHOOK_URL" \ + -H "Content-Type: application/json" \ + -H "X-Hub-Signature: sha256=$SIGNATURE" \ + -d "$PAYLOAD" \ + --insecure \ No newline at end of file diff --git a/frontend-next-migration/src/preparedPages/AboutPage/ui/About.tsx b/frontend-next-migration/src/preparedPages/AboutPage/ui/About.tsx index effc885c7..e4c7cd182 100644 --- a/frontend-next-migration/src/preparedPages/AboutPage/ui/About.tsx +++ b/frontend-next-migration/src/preparedPages/AboutPage/ui/About.tsx @@ -67,7 +67,7 @@ const About = (props: Props) => { >