From 0d00490e7154944d2f38d6246dcec1aac2f375da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valdemar=20=C3=85storp=20Beere?= <valdemb@stud.ntnu.no> Date: Thu, 2 May 2024 13:55:38 +0200 Subject: [PATCH] fix(format): Ran format --- src/App.vue | 53 +++---- src/assets/base.css | 12 +- src/components/CardChallengeSavingsPath.vue | 3 +- src/components/FormRegister.vue | 11 +- src/components/NavBarComponent.vue | 31 ++-- src/components/PageControl.vue | 12 +- src/components/ProgressBar.vue | 3 +- src/components/SavingsPath.vue | 78 +++++----- .../__tests__/savingsPathTest.spec.ts | 123 --------------- src/views/HomeView.vue | 1 - src/views/ManageChallengeView.vue | 142 ++++++++---------- src/views/ManageGoalView.vue | 127 +++++++--------- src/views/UserChallengesView.vue | 11 +- src/views/UserGoalsView.vue | 20 +-- src/views/ViewChallengeView.vue | 25 ++- src/views/ViewGoalView.vue | 19 +-- 16 files changed, 258 insertions(+), 413 deletions(-) delete mode 100644 src/components/__tests__/savingsPathTest.spec.ts diff --git a/src/App.vue b/src/App.vue index 63ea821..6713c1c 100644 --- a/src/App.vue +++ b/src/App.vue @@ -23,7 +23,7 @@ const backgroundImageStyle = computed(() => { } } else { return { - backgroundImage: "none" + backgroundImage: 'none' } } }) @@ -143,30 +143,31 @@ const helpMessages = computed(() => { <template> <div - class="min-h-screen bg-left-bottom bg-phone md:bg-pc bg-no-repeat" - :style="backgroundImageStyle"> + class="min-h-screen bg-left-bottom bg-phone md:bg-pc bg-no-repeat" + :style="backgroundImageStyle" + > <HelpComponent v-if="showHelp" :speech="helpMessages" /> - <NavBarComponent v-if="showNavBar" /> - - <main class="mb-10 "> - <RouterView /> - </main> + <NavBarComponent v-if="showNavBar" /> + + <main class="mb-10"> + <RouterView /> + </main> </div> - </template> - - <style> - nav { - display: flex; - justify-content: center; - gap: 1rem; - margin: 1rem 0; - } - - nav a.router-link-exact-active { - color: var(--color-text); - } - - nav a.router-link-exact-active:hover { - background-color: transparent; - } - </style> \ No newline at end of file +</template> + +<style> +nav { + display: flex; + justify-content: center; + gap: 1rem; + margin: 1rem 0; +} + +nav a.router-link-exact-active { + color: var(--color-text); +} + +nav a.router-link-exact-active:hover { + background-color: transparent; +} +</style> diff --git a/src/assets/base.css b/src/assets/base.css index 4d25b57..db17414 100644 --- a/src/assets/base.css +++ b/src/assets/base.css @@ -33,14 +33,14 @@ --section-gap: 160px; } -input[type="number"]::-webkit-inner-spin-button, -input[type="number"]::-webkit-outer-spin-button { - -webkit-appearance: none; - margin: 0; +input[type='number']::-webkit-inner-spin-button, +input[type='number']::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; } -input[type="number"] { - -moz-appearance: textfield; /* Firefox */ +input[type='number'] { + -moz-appearance: textfield; /* Firefox */ } *, diff --git a/src/components/CardChallengeSavingsPath.vue b/src/components/CardChallengeSavingsPath.vue index d48b508..cb34ba2 100644 --- a/src/components/CardChallengeSavingsPath.vue +++ b/src/components/CardChallengeSavingsPath.vue @@ -107,6 +107,7 @@ const editChallenge = (challenge: Challenge) => { } // Helper methods to get icons const getChallengeIcon = (challenge: Challenge): string => { - return `src/assets/${challenge.type.toLowerCase()}.png` + //TODO change to challenge.icon + return `src/assets/coffee.png` } </script> diff --git a/src/components/FormRegister.vue b/src/components/FormRegister.vue index ebaaf16..2863b6a 100644 --- a/src/components/FormRegister.vue +++ b/src/components/FormRegister.vue @@ -137,7 +137,9 @@ watch( </div> <input v-model="confirm" - :class="{ 'border-2 border-lime-400': password == confirm && '' !== confirm.valueOf() }" + :class="{ + 'border-2 border-lime-400': password == confirm && '' !== confirm.valueOf() + }" class="mt-2" name="confirm" placeholder="Bekreft passord" @@ -145,7 +147,12 @@ watch( /> </div> <div class="flex flex-row gap-5"> - <button :disabled="isFormInvalid" class="grow-0 primary" name="submit" @click="submitForm"> + <button + :disabled="isFormInvalid" + class="grow-0 primary" + name="submit" + @click="submitForm" + > Registrer deg </button> <p>{{ errorMessage }}</p> diff --git a/src/components/NavBarComponent.vue b/src/components/NavBarComponent.vue index 795eca5..9248166 100644 --- a/src/components/NavBarComponent.vue +++ b/src/components/NavBarComponent.vue @@ -23,13 +23,14 @@ </div> <div v-if="!isHamburger" class="flex justify-center w-40"> - <button class="primary bg-[#95e35d] logout focus:ring focus:ring-black-300" @click="openModal">Logg ut</button> + <button + class="primary bg-[#95e35d] logout focus:ring focus:ring-black-300" + @click="openModal" + > + Logg ut + </button> </div> - <button - class="primary logout" - v-if="isHamburger" - @click="toggleMenu">☰ - </button> + <button class="primary logout" v-if="isHamburger" @click="toggleMenu">☰</button> </nav> <div v-if="hamburgerOpen" class="flex flex-col bg-white border border-slate-300 z-50"> @@ -39,9 +40,7 @@ >💰Spareutfordringer</router-link > <router-link to="/profil" @click="hamburgerOpen = false">ðŸ¤Profil</router-link> - <button class="focus:ring focus:ring-black-300" @click="openModal"> - Logg ut - </button> + <button class="focus:ring focus:ring-black-300" @click="openModal">Logg ut</button> </div> <ModalComponent :title="'Vil du logge ut?'" @@ -50,18 +49,8 @@ @close="isModalOpen = false" > <template v-slot:buttons> - <button - @click="logout" - class="primary" - > - Logg ut - </button> - <button - @click="closeModal" - class="primary danger" - > - Avbryt - </button> + <button @click="logout" class="primary">Logg ut</button> + <button @click="closeModal" class="primary danger">Avbryt</button> </template> </ModalComponent> </template> diff --git a/src/components/PageControl.vue b/src/components/PageControl.vue index 93ad991..921f2c9 100644 --- a/src/components/PageControl.vue +++ b/src/components/PageControl.vue @@ -17,15 +17,19 @@ defineProps({ <template> <div v-if="totalPages > 0" class="flex justify-center gap-4"> - <button + <button class="primary" - :disabled="currentPage === 0" @click="onPageChange(currentPage - 1)"> + :disabled="currentPage === 0" + @click="onPageChange(currentPage - 1)" + > Forrige </button> <p>{{ currentPage + 1 }} / {{ totalPages }}</p> - <button + <button class="primary" - :disabled="currentPage === totalPages - 1" @click="onPageChange(currentPage + 1)"> + :disabled="currentPage === totalPages - 1" + @click="onPageChange(currentPage + 1)" + > Neste </button> </div> diff --git a/src/components/ProgressBar.vue b/src/components/ProgressBar.vue index 65dd661..3a29f2f 100644 --- a/src/components/ProgressBar.vue +++ b/src/components/ProgressBar.vue @@ -6,8 +6,7 @@ defineProps({ <template> <div class="w-full bg-gray-200 rounded-full overflow-hidden"> - <div :style="{ width: completion + '%' }" class="bg-lime-400 h-2 rounded-full"> - </div> + <div :style="{ width: completion + '%' }" class="bg-lime-400 h-2 rounded-full"></div> </div> </template> diff --git a/src/components/SavingsPath.vue b/src/components/SavingsPath.vue index 81afbc3..ba90e65 100644 --- a/src/components/SavingsPath.vue +++ b/src/components/SavingsPath.vue @@ -20,7 +20,7 @@ </button> <div class="h-1 w-4/6 mx-auto my-2 opacity-10"></div> <div - v-if="challenges" + v-if="challengesLocal" ref="containerRef" class="container relative pt-6 w-4/5 bg-cover bg-[center] md:[background-position: center;] mx-auto md:w-4/5 no-scrollbar h-full max-h-[60vh] md:max-h-[60vh] md:min-w-2/5 overflow-y-auto border-2 border-transparent rounded-xl bg-white shadow-lg shadow-slate-400" style="background-image: url('src/assets/backgroundSavingsPath.png')" @@ -30,7 +30,7 @@ </div> <div - v-for="(challenge, index) in challenges" + v-for="(challenge, index) in challengesLocal" :key="challenge.id" class="flex flex-col items-center" :ref="(el) => assignRef(el, challenge, index)" @@ -61,7 +61,7 @@ ></img-gif-template> </div> <card-challenge-savings-path - :goal="goal!" + :goal="goalLocal!" :challenge="challenge" @update-challenge="handleChallengeUpdate" ></card-challenge-savings-path> @@ -84,7 +84,7 @@ </div> </div> <!-- Piggy Steps, centered --> - <div v-if="index !== challenges.length" class="flex justify-center w-full"> + <div v-if="index !== challengesLocal.length" class="flex justify-center w-full"> <img :src="getPigStepsIcon()" :class="{ 'transform scale-x-[-1]': index % 2 === 0 }" @@ -94,14 +94,14 @@ </div> <div - v-if="index === challenges.length - 1 && index % 2 === 0" + v-if="index === challengesLocal.length - 1 && index % 2 === 0" class="flex flex-row mt-2" > <button class="text-2xl ml-48" @click="addSpareUtfordring">+</button> <p class="">Legg til <br />Spareutfordring</p> </div> <div - v-else-if="index === challenges.length - 1 && index % 2 !== 0" + v-else-if="index === challengesLocal.length - 1 && index % 2 !== 0" class="mr-20 flex flex-row" > <button class="text-2xl ml-10 rounded-full" @click="addSpareUtfordring"> @@ -118,11 +118,15 @@ /> </div> <!-- Goal --> - <div v-if="goal" class="flex flex-row justify-around m-t-2 pt-6 w-full mx-auto"> + <div v-if="goalLocal" class="flex flex-row justify-around m-t-2 pt-6 w-full mx-auto"> <div class="grid grid-rows-2 grid-flow-col gap 4"> - <div class="row-span-3 cursor-pointer" @click="editGoal(goal)"> - <img :src="getGoalIcon(goal)" class="w-12 h-12 mx-auto" :alt="goal.title" /> - <div class="text-lg font-bold" data-cy="goal-title">{{ goal.title }}</div> + <div class="row-span-3 cursor-pointer" @click="editGoal(goalLocal)"> + <img + :src="getGoalIcon(goalLocal)" + class="w-12 h-12 mx-auto" + :alt="goalLocal.title" + /> + <div class="text-lg font-bold" data-cy="goal-title">{{ goalLocal.title }}</div> </div> </div> <div class="flex flex-col items-end"> @@ -134,7 +138,7 @@ ref="targetRef" class="bg-yellow-400 px-4 py-1 rounded-full text-black font-bold" > - {{ goal.saved }}kr / {{ goal.target }}kr + {{ goalLocal.saved }}kr / {{ goalLocal.target }}kr </div> </div> </div> @@ -147,8 +151,8 @@ class="max-w-20 max-h-20 absolute opacity-0" /> <img - v-if="goal" - :src="getGoalIcon(goal)" + v-if="goalLocal" + :src="getGoalIcon(goalLocal)" alt="could not load" ref="goalIconRef" class="shadow-sm shadow-amber-300 max-w-20 max-h-20 absolute opacity-0" @@ -183,8 +187,8 @@ interface Props { } const props = defineProps<Props>() -const challenges = ref<Challenge[]>() -let goal: Goal | null | undefined = reactive({ +const challengesLocal = ref<Challenge[]>() +let goalLocal: Goal | null | undefined = reactive({ title: '', // Default empty string to prevent undefined errors saved: 0, target: 0 @@ -197,8 +201,8 @@ const componentKey = ref<number>(0) onMounted(async () => { window.addEventListener('resize', handleWindowSizeChange) handleWindowSizeChange() - challenges.value = props.challenges - goal = props.goal + challengesLocal.value = props.challenges + goalLocal = props.goal sortChallenges() allChallengesCompleted() // Delay the execution of the following logic by 300ms @@ -221,7 +225,7 @@ onMounted(async () => { loadAnimatedStates() // Get completed challenge IDs, ensuring that only defined IDs are considered - const completedChallenges = challenges.value + const completedChallenges = challengesLocal.value .filter((challenge) => challenge.completion! >= 100 && challenge.id !== undefined) .map((challenge) => challenge.id as number) // Use 'as number' to assert that ids are numbers after the check @@ -245,10 +249,10 @@ onUnmounted(() => { }) const handleChallengeUpdate = (updatedChallenge: Challenge) => { - if (challenges.value) { - const index = challenges.value.findIndex((c) => c.id === updatedChallenge.id) + if (challengesLocal.value) { + const index = challengesLocal.value.findIndex((c) => c.id === updatedChallenge.id) if (index !== -1) { - challenges.value[index] = { ...updatedChallenge } + challengesLocal.value[index] = { ...updatedChallenge } } if ( @@ -259,7 +263,7 @@ const handleChallengeUpdate = (updatedChallenge: Challenge) => { saveAnimatedStateChallenge(updatedChallenge) } - if (goal) { + if (goalLocal) { incrementGoalSaved(updatedChallenge) // Force component update right here might be more appropriate componentKey.value++ @@ -268,21 +272,21 @@ const handleChallengeUpdate = (updatedChallenge: Challenge) => { } const incrementGoalSaved = async (challenge: Challenge) => { - if (goal) { + if (goalLocal) { // Correct the addition mistake and remove setTimeout - goal.saved = goal.saved + challenge.perPurchase + goalLocal.saved = goalLocal.saved + challenge.perPurchase await nextTick() // Only add the perPurchase amount - const completion = (goal.saved / goal.target) * 100 - if (completion >= 100 && !animatedGoals.value.includes(goal.id as number)) { - animateGoal(goal) + const completion = (goalLocal.saved / goalLocal.target) * 100 + if (completion >= 100 && !animatedGoals.value.includes(goalLocal.id as number)) { + animateGoal(goalLocal) setTimeout(() => { goalStore.getUserGoals() - goal = goalStore.priorityGoal + goalLocal = goalStore.priorityGoal }, 4000) // Keep this delay only for the store update and goal switch } else { await goalStore.getUserGoals() - goal = goalStore.priorityGoal + goalLocal = goalStore.priorityGoal } } } @@ -301,8 +305,8 @@ const addSpareUtfordring = () => { */ const allChallengesCompleted = () => { // Assuming challenges.value is an array of challenge objects - if (challenges.value) { - for (const challenge of challenges.value) { + if (challengesLocal.value) { + for (const challenge of challengesLocal.value) { if (challenge.completion !== 100) { return false // If any challenge is not completed, return false } @@ -592,7 +596,7 @@ const getPigStepsIcon = () => { } const goToEditGoal = () => { - router.push({ name: 'edit-goal', params: { id: goal?.id } }) + router.push({ name: 'edit-goal', params: { id: goalLocal?.id } }) } const editGoal = (goal: Goal) => { @@ -604,8 +608,8 @@ const editGoal = (goal: Goal) => { */ const sortChallenges = () => { - if (challenges.value) { - challenges.value.sort((a, b) => { + if (challengesLocal.value) { + challengesLocal.value.sort((a, b) => { // First, sort by completion status: non-completed (less than 100) before completed (100) if (a.completion !== 100 && b.completion === 100) { return 1 // 'a' is not completed and 'b' is completed, 'a' should come first @@ -643,10 +647,10 @@ const handleWindowSizeChange = () => { */ const scrollToFirstUncompleted = () => { - if (challenges.value) { + if (challengesLocal.value) { let found = false - for (let i = 0; i < challenges.value.length; i++) { - if (challenges.value[i].completion! < 100) { + for (let i = 0; i < challengesLocal.value.length; i++) { + if (challengesLocal.value[i].completion! < 100) { const refKey = `uncompleted-${i}` if (elementRefs[refKey]) { elementRefs[refKey]!.scrollIntoView({ behavior: 'smooth', block: 'start' }) diff --git a/src/components/__tests__/savingsPathTest.spec.ts b/src/components/__tests__/savingsPathTest.spec.ts deleted file mode 100644 index 40739f5..0000000 --- a/src/components/__tests__/savingsPathTest.spec.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest' -import { mount } from '@vue/test-utils' -import { createPinia, setActivePinia } from 'pinia' -import SavingsPath from '@/components/SavingsPath.vue' - -vi.mock('canvas-confetti', () => ({ - default: vi.fn(() => ({ - reset: vi.fn(), - addFettis: vi.fn(), - render: vi.fn(), - clear: vi.fn() - })) -})) -const mocks = vi.hoisted(() => ({ - get: vi.fn(), - post: vi.fn() -})) - -vi.mock('axios', async (importActual) => { - const actual = await importActual<typeof import('axios')>() - - return { - default: { - ...actual.default, - create: vi.fn(() => ({ - ...actual.default.create(), - get: mocks.get, - post: mocks.post - })) - } - } -}) - -describe('SavingsPath Component', () => { - let wrapper: any - const pinia = createPinia() - - beforeEach(() => { - window.HTMLElement.prototype.scrollIntoView = function () {} - setActivePinia(pinia) - wrapper = mount(SavingsPath, { - global: { - plugins: [pinia] - }, - props: { - challenges: [ - { - id: 1, - title: 'Test challenge', - perPurchase: 20, - saved: 100, - target: 1000, - description: 'Test description', - due: '2022-01-01T00:00:00Z', - createdOn: '2021-01-01T00:00:00Z', - type: 'Challenge type', - completion: 10 - } - ], - goal: { - id: 1, - title: 'Test goal', - saved: 100, - target: 1000, - description: 'Test description', - due: '2022-01-01T00:00:00Z', - createdOn: '2021-01-01T00:00:00Z', - completion: 10 - } - } - }) - }) - - describe('Initial Render', () => { - it('should render challenge and goal details correctly', async () => { - await wrapper.vm.$nextTick() - const challengeText = wrapper.text() - expect(challengeText).toContain('Test challenge') - expect(challengeText).toContain('100kr / 1000kr') - expect(challengeText).toContain('Test goal') - expect(challengeText).toContain('100kr / 1000kr') - }) - - it('should display the correct number of challenge elements', () => { - const challengeElements = wrapper.findAll('[data-cy="challenge-title"]') - expect(challengeElements.length).toBe(1) - }) - }) - - describe('User Interactions', () => { - it('should update challenge progress when increment button is clicked', async () => { - await wrapper.vm.$nextTick() - const incrementButton = wrapper.find('[data-cy="increment-challenge1"]') - expect(incrementButton.exists()).toBe(true) - await incrementButton.trigger('click') - expect(wrapper.vm.challenges[0].saved).toBe(120) - }) - }) - - describe('State Management', () => { - it('should react to changes in challenge completion status', async () => { - // Initially incomplete - let progressBar = wrapper.find('.bg-green-600') - expect(progressBar.element.style.width).toBe('10%') - - // Update challenge to be almost complete - await wrapper.setProps({ - challenges: [ - { - ...wrapper.props().challenges[0], - saved: 900, - completion: 90 - } - ] - }) - await wrapper.vm.$nextTick() - await wrapper.vm.$nextTick() - - progressBar = wrapper.find('.bg-green-600') - expect(progressBar.element.style.width).toBe('90%') - }) - }) -}) diff --git a/src/views/HomeView.vue b/src/views/HomeView.vue index bdc50b3..2aae863 100644 --- a/src/views/HomeView.vue +++ b/src/views/HomeView.vue @@ -50,7 +50,6 @@ const challengeStore = useChallengeStore() const speech = ref<string[]>([]) const challenges = ref<Challenge[]>([]) -const goals = ref<Goal[]>([]) const showWelcome = ref<boolean>(false) const goal = ref<Goal | null | undefined>(null) diff --git a/src/views/ManageChallengeView.vue b/src/views/ManageChallengeView.vue index 20fcdfd..a600840 100644 --- a/src/views/ManageChallengeView.vue +++ b/src/views/ManageChallengeView.vue @@ -8,22 +8,20 @@ import ModalComponent from '@/components/ModalComponent.vue' const router = useRouter() -const modalTitle = ref(''); -const modalMessage = ref(''); -const confirmModalOpen = ref(false); -const errorModalOpen = ref(false); +const modalTitle = ref('') +const modalMessage = ref('') +const confirmModalOpen = ref(false) +const errorModalOpen = ref(false) const oneWeekFromNow = new Date() oneWeekFromNow.setDate(oneWeekFromNow.getDate() + 7) const minDate = new Date(new Date().setDate(new Date().getDate() + 1)).toISOString().slice(0, 10) const selectedDate = ref<string>(minDate) - const thirtyDaysFromNow = new Date() thirtyDaysFromNow.setDate(thirtyDaysFromNow.getDate() + 30) const maxDate = thirtyDaysFromNow.toISOString().slice(0, 10) - const challengeInstance = ref<Challenge>({ title: '', perPurchase: 0, @@ -33,10 +31,9 @@ const challengeInstance = ref<Challenge>({ due: '' }) - watch(selectedDate, (newDate) => { - challengeInstance.value.due = newDate; -}); + challengeInstance.value.due = newDate +}) const isEdit = computed(() => router.currentRoute.value.name === 'edit-challenge') const pageTitle = computed(() => (isEdit.value ? 'Rediger utfordring🎨' : 'Ny utfordring🎨')) @@ -46,48 +43,48 @@ const completion = computed( ) function validateInputs() { - const errors = []; + const errors = [] - challengeInstance.value.due = selectedDate.value + 'T23:59:59.999Z'; + challengeInstance.value.due = selectedDate.value + 'T23:59:59.999Z' if (!challengeInstance.value.title || challengeInstance.value.title.length > 20) { - errors.push("Tittelen mÃ¥ være mellom 1 og 20 tegn."); + errors.push('Tittelen mÃ¥ være mellom 1 og 20 tegn.') } if (challengeInstance.value.description.length > 280) { - errors.push("Beskrivelsen mÃ¥ være under 280 tegn."); + errors.push('Beskrivelsen mÃ¥ være under 280 tegn.') } if (challengeInstance.value.target <= 0) { - errors.push("MÃ¥lbeløpet mÃ¥ være større enn 0."); + errors.push('MÃ¥lbeløpet mÃ¥ være større enn 0.') } if (new Date(challengeInstance.value.due) < new Date(minDate)) { - errors.push("Forfallsdatoen mÃ¥ være minst en uke frem i tid."); + errors.push('Forfallsdatoen mÃ¥ være minst en uke frem i tid.') } if (challengeInstance.value.perPurchase <= 0) { - errors.push("Pris per sparing mÃ¥ være større enn 0."); + errors.push('Pris per sparing mÃ¥ være større enn 0.') } - return errors; + return errors } -const submitAction = async() => { - const errors = validateInputs(); - if(errors.length > 0) { - const formatErrors = errors.join('\n'); - modalTitle.value = 'Oops! Noe er feil med det du har fylt ut🚨'; - modalMessage.value = formatErrors; - errorModalOpen.value = true; - return; +const submitAction = async () => { + const errors = validateInputs() + if (errors.length > 0) { + const formatErrors = errors.join('\n') + modalTitle.value = 'Oops! Noe er feil med det du har fylt ut🚨' + modalMessage.value = formatErrors + errorModalOpen.value = true + return } try { if (isEdit.value) { - updateChallenge(); + updateChallenge() } else { - createChallenge(); + createChallenge() } } catch (error) { - console.error(error); - modalTitle.value = 'Systemfeil'; - modalMessage.value = 'En feil oppstod under lagring av utfordringen.'; - errorModalOpen.value = true; + console.error(error) + modalTitle.value = 'Systemfeil' + modalMessage.value = 'En feil oppstod under lagring av utfordringen.' + errorModalOpen.value = true } } @@ -135,15 +132,16 @@ const updateChallenge = () => { } const cancelCreation = () => { - if (challengeInstance.value.title !== '' || + if ( + challengeInstance.value.title !== '' || challengeInstance.value.description !== '' || - challengeInstance.value.perPurchase !== 0 || - challengeInstance.value.saved !== 0 || - challengeInstance.value.target !== 0) - { - modalTitle.value = 'Du er i ferd med Ã¥ avbryte redigeringen🚨'; - modalMessage.value = 'Er du sikker pÃ¥ at du vil avbryte?'; - confirmModalOpen.value = true; + challengeInstance.value.perPurchase !== 0 || + challengeInstance.value.saved !== 0 || + challengeInstance.value.target !== 0 + ) { + modalTitle.value = 'Du er i ferd med Ã¥ avbryte redigeringen🚨' + modalMessage.value = 'Er du sikker pÃ¥ at du vil avbryte?' + confirmModalOpen.value = true } else { router.push({ name: 'challenges' }) } @@ -151,9 +149,8 @@ const cancelCreation = () => { const confirmCancel = () => { router.push({ name: 'challenges' }) - confirmModalOpen.value = false; + confirmModalOpen.value = false } - </script> <template> @@ -224,24 +221,20 @@ const confirmCancel = () => { type="date" /> </div> - + <div class="flex flex-col"> <p>Last opp ikon for utfordringen📸</p> - <button class="mt-2 font-bold cursor-pointer transition-transform duration-300 ease-in-out hover:scale-110 hover:opacity-90">💾</button> + <button + class="mt-2 font-bold cursor-pointer transition-transform duration-300 ease-in-out hover:scale-110 hover:opacity-90" + > + 💾 + </button> </div> </div> <div class="flex flex-row justify-between w-full"> + <button class="primary danger" @click="cancelCreation" v-text="'Avbryt'" /> - <button - class="primary danger" - @click="cancelCreation" - v-text="'Avbryt'" - /> - - <button - class="primary" - @click="submitAction" - v-text="submitButton" /> + <button class="primary" @click="submitAction" v-text="submitButton" /> </div> <ModalComponent :title="modalTitle" @@ -249,18 +242,13 @@ const confirmCancel = () => { :isModalOpen="errorModalOpen" @close="errorModalOpen = false" > - <template v-slot:input> - <div class="flex justify-center items-center"> - <div class="flex flex-col gap-5"> - <button - class="primary" - @click="errorModalOpen = false" - > - Lukk - </button> + <template v-slot:input> + <div class="flex justify-center items-center"> + <div class="flex flex-col gap-5"> + <button class="primary" @click="errorModalOpen = false">Lukk</button> + </div> </div> - </div> - </template> + </template> </ModalComponent> <ModalComponent @@ -269,24 +257,16 @@ const confirmCancel = () => { :isModalOpen="confirmModalOpen" @close="confirmModalOpen = false" > - <template v-slot:input> - <div class="flex justify-center items-center"> - <div class="flex flex-col gap-5"> - <button - class="primary" - @click="confirmCancel" - > - Bekreft - </button> - <button - class="primary danger" - @click="confirmModalOpen = false" - > - Avbryt - </button> + <template v-slot:input> + <div class="flex justify-center items-center"> + <div class="flex flex-col gap-5"> + <button class="primary" @click="confirmCancel">Bekreft</button> + <button class="primary danger" @click="confirmModalOpen = false"> + Avbryt + </button> + </div> </div> - </div> - </template> + </template> </ModalComponent> </div> </div> diff --git a/src/views/ManageGoalView.vue b/src/views/ManageGoalView.vue index f3fd1a1..d2d8e75 100644 --- a/src/views/ManageGoalView.vue +++ b/src/views/ManageGoalView.vue @@ -11,13 +11,11 @@ const router = useRouter() const minDate = new Date(new Date().setDate(new Date().getDate() + 1)).toISOString().slice(0, 10) const selectedDate = ref<string>(minDate) - const modalMessage = ref<string>('') const modalTitle = ref<string>('') const errorModalOpen = ref<boolean>(false) const confirmModalOpen = ref<boolean>(false) - const goalInstance = ref<Goal>({ title: '', saved: 0, @@ -27,8 +25,8 @@ const goalInstance = ref<Goal>({ }) watch(selectedDate, (newDate) => { - goalInstance.value.due = newDate; -}); + goalInstance.value.due = newDate +}) const isEdit = computed(() => router.currentRoute.value.name === 'edit-goal') const pageTitle = computed(() => (isEdit.value ? 'Rediger sparemÃ¥l🎨' : 'Nytt sparemÃ¥l🎨')) @@ -36,55 +34,54 @@ const submitButton = computed(() => (isEdit.value ? 'Oppdater' : 'Opprett')) const completion = computed(() => (goalInstance.value.saved / goalInstance.value.target) * 100) function validateInputs() { - const errors = []; + const errors = [] - goalInstance.value.due = selectedDate.value + 'T23:59:59.999Z'; + goalInstance.value.due = selectedDate.value + 'T23:59:59.999Z' if (!goalInstance.value.title) { - errors.push('Tittel mÃ¥ fylles ut'); + errors.push('Tittel mÃ¥ fylles ut') } - if (!goalInstance.value.target ) { - errors.push('MÃ¥lbeløp mÃ¥ fylles ut'); + if (!goalInstance.value.target) { + errors.push('MÃ¥lbeløp mÃ¥ fylles ut') } if (!goalInstance.value.due) { - errors.push('Forfallsdato mÃ¥ fylles ut'); + errors.push('Forfallsdato mÃ¥ fylles ut') } if (goalInstance.value.target < 1) { - errors.push('MÃ¥lbeløp mÃ¥ være større enn 0'); + errors.push('MÃ¥lbeløp mÃ¥ være større enn 0') } if (goalInstance.value.saved < 0) { - errors.push('Sparebeløp kan ikke være negativt'); + errors.push('Sparebeløp kan ikke være negativt') } if (goalInstance.value.saved > goalInstance.value.target) { - errors.push('Sparebeløp kan ikke være større enn mÃ¥lbeløp'); + errors.push('Sparebeløp kan ikke være større enn mÃ¥lbeløp') } - return errors; - + return errors } -const submitAction = async() => { - const errors = validateInputs(); - if(errors.length > 0) { - const formatErrors = errors.join('\n'); - modalTitle.value = 'Oops! Noe er feil med det du har fylt ut🚨'; - modalMessage.value = formatErrors.replace(/\n/g, "<br>") - errorModalOpen.value = true; - return; +const submitAction = async () => { + const errors = validateInputs() + if (errors.length > 0) { + const formatErrors = errors.join('\n') + modalTitle.value = 'Oops! Noe er feil med det du har fylt ut🚨' + modalMessage.value = formatErrors.replace(/\n/g, '<br>') + errorModalOpen.value = true + return } try { if (isEdit.value) { - updateGoal(); + updateGoal() } else { - createGoal(); + createGoal() } } catch (error) { - console.error(error); - modalTitle.value = 'Systemfeil'; - modalMessage.value = 'En feil oppstod under lagring av utfordringen.'; - errorModalOpen.value = true; + console.error(error) + modalTitle.value = 'Systemfeil' + modalMessage.value = 'En feil oppstod under lagring av utfordringen.' + errorModalOpen.value = true } } @@ -145,13 +142,15 @@ const deleteGoal = () => { } function cancelCreation() { - if (goalInstance.value.title !== '' || - goalInstance.value.description !== '' || + if ( + goalInstance.value.title !== '' || + goalInstance.value.description !== '' || goalInstance.value.target !== 0 || - selectedDate.value !== '') { - modalTitle.value = 'Du er i ferd med Ã¥ avbryte redigeringen🚨'; - modalMessage.value = 'Er du sikker pÃ¥ at du vil avbryte?'; - confirmModalOpen.value = true; + selectedDate.value !== '' + ) { + modalTitle.value = 'Du er i ferd med Ã¥ avbryte redigeringen🚨' + modalMessage.value = 'Er du sikker pÃ¥ at du vil avbryte?' + confirmModalOpen.value = true } else { router.push({ name: 'goals' }) } @@ -159,7 +158,7 @@ function cancelCreation() { const confirmCancel = () => { router.push({ name: 'goals' }) - confirmModalOpen.value = false; + confirmModalOpen.value = false } </script> @@ -216,7 +215,11 @@ const confirmCancel = () => { </div> <div class="flex flex-col"> <p>Last opp ikon for utfordringen📸</p> - <button class="mt-2 font-bold cursor-pointer transition-transform duration-300 ease-in-out hover:scale-110 hover:opacity-90">💾</button> + <button + class="mt-2 font-bold cursor-pointer transition-transform duration-300 ease-in-out hover:scale-110 hover:opacity-90" + > + 💾 + </button> </div> </div> @@ -233,10 +236,7 @@ const confirmCancel = () => { @click="cancelCreation" v-text="'Avbryt'" /> - <button - class="primary" - @click="submitAction" v-text="submitButton" - /> + <button class="primary" @click="submitAction" v-text="submitButton" /> </div> <ModalComponent :title="modalTitle" @@ -244,18 +244,13 @@ const confirmCancel = () => { :isModalOpen="errorModalOpen" @close="errorModalOpen = false" > - <template v-slot:input> - <div class="flex justify-center items-center"> - <div class="flex flex-col gap-5"> - <button - class="primary" - @click="errorModalOpen = false" - > - Lukk - </button> + <template v-slot:input> + <div class="flex justify-center items-center"> + <div class="flex flex-col gap-5"> + <button class="primary" @click="errorModalOpen = false">Lukk</button> + </div> </div> - </div> - </template> + </template> </ModalComponent> <ModalComponent @@ -264,24 +259,16 @@ const confirmCancel = () => { :isModalOpen="confirmModalOpen" @close="confirmModalOpen = false" > - <template v-slot:input> - <div class="flex justify-center items-center"> - <div class="flex flex-col gap-5"> - <button - class="primary" - @click="confirmCancel" - > - Bekreft - </button> - <button - class="primary danger" - @click="confirmModalOpen = false" - > - Avbryt - </button> + <template v-slot:input> + <div class="flex justify-center items-center"> + <div class="flex flex-col gap-5"> + <button class="primary" @click="confirmCancel">Bekreft</button> + <button class="primary danger" @click="confirmModalOpen = false"> + Avbryt + </button> + </div> </div> - </div> - </template> + </template> </ModalComponent> </div> </div> @@ -291,4 +278,4 @@ const confirmCancel = () => { .no-rezise { resize: none; } -</style> \ No newline at end of file +</style> diff --git a/src/views/UserChallengesView.vue b/src/views/UserChallengesView.vue index dbc1e82..2e05bb0 100644 --- a/src/views/UserChallengesView.vue +++ b/src/views/UserChallengesView.vue @@ -50,9 +50,7 @@ onMounted(async () => { <h1 class="font-bold text-center">Dine utfordringer</h1> <div class="flex flex-col gap-5 items-center"> <div class="flex flex-row gap-5"> - <button - class="primary" - @click="router.push({ name: 'new-challenge' })"> + <button class="primary" @click="router.push({ name: 'new-challenge' })"> Opprett en ny utfordring </button> </div> @@ -64,9 +62,7 @@ onMounted(async () => { :key="challenge.id" :challenge-instance="challenge" /> - <p v-if="!activeChallenges"> - Du har ingen aktive spareutfordringer😢 - </p> + <p v-if="!activeChallenges">Du har ingen aktive spareutfordringer😢</p> </div> <PageControl :currentPage="currentPageActive" @@ -91,5 +87,4 @@ onMounted(async () => { </div> </template> -<style scoped> -</style> \ No newline at end of file +<style scoped></style> diff --git a/src/views/UserGoalsView.vue b/src/views/UserGoalsView.vue index b41e7c4..734f469 100644 --- a/src/views/UserGoalsView.vue +++ b/src/views/UserGoalsView.vue @@ -60,9 +60,9 @@ const changeOrder = async () => { <template> <div class="flex flex-col gap-5 items-center"> <h1 class="font-bold m-0">Dine sparemÃ¥l</h1> - <button - class="primary" - @click="router.push({ name: 'new-goal' })">Opprett et nytt sparemÃ¥l</button> + <button class="primary" @click="router.push({ name: 'new-goal' })"> + Opprett et nytt sparemÃ¥l + </button> <h2 class="font-bold m-0">Aktive sparemÃ¥l🚀</h2> <p v-if="activeGoals.length === 0">Du har ingen aktive sparemÃ¥l</p> <draggable @@ -87,18 +87,20 @@ const changeOrder = async () => { </draggable> <button class="primary secondary" - :disabled="activeGoals.length === 0" @click="changeOrder()"> + :disabled="activeGoals.length === 0" + @click="changeOrder()" + > {{ isDraggable ? 'Lagre rekkefølge' : 'Endre rekkefølge' }} </button> <h2 class="font-bold m-0">Fullførte sparemÃ¥l💯</h2> <p v-if="completedGoals.length === 0">Du har ingen fullførte sparemÃ¥l😢</p> <div v-else class="flex flex-row flex-wrap justify-center gap-10"> - <CardGoal + <CardGoal class="border-2 border-slate-200 hover:bg-slate-50" - v-for="goal in completedGoals" - :key="goal.id" - :goal-instance="goal" - /> + v-for="goal in completedGoals" + :key="goal.id" + :goal-instance="goal" + /> </div> <PageControl :current-page="currentPage" diff --git a/src/views/ViewChallengeView.vue b/src/views/ViewChallengeView.vue index 76f11a2..924d5ae 100644 --- a/src/views/ViewChallengeView.vue +++ b/src/views/ViewChallengeView.vue @@ -81,10 +81,10 @@ const completeChallenge = () => { <div class="flex flex-row flex-wrap items-center justify-center gap-10"> <div class="flex flex-col gap-5 max-w-96"> <button - class="w-min bg-transparent rounded-lg font-bold left-10 cursor-pointer transition-transform duration-300 ease-in-out hover:scale-110 hover:opacity-100 justify-start" + class="w-min bg-transparent rounded-lg font-bold left-10 cursor-pointer transition-transform duration-300 ease-in-out hover:scale-110 hover:opacity-100 justify-start" @click="router.push({ name: 'challenges', params: { id: challengeInstance.id } })" > - 👈Oversikt + 👈Oversikt </button> <div @@ -108,17 +108,16 @@ const completeChallenge = () => { </p> <div class="justify-center pl-20"> <button - class="primary danger mt-2 rounded-2xl p-2 w-40" - @click=" - authInterceptor - .delete(`/challenges/${challengeInstance.id}`) - .then(() => router.push({ name: 'challenges' })) - .catch((error) => console.error(error)) - " - > - Slett - </button> - + class="primary danger mt-2 rounded-2xl p-2 w-40" + @click=" + authInterceptor + .delete(`/challenges/${challengeInstance.id}`) + .then(() => router.push({ name: 'challenges' })) + .catch((error) => console.error(error)) + " + > + Slett + </button> </div> </div> diff --git a/src/views/ViewGoalView.vue b/src/views/ViewGoalView.vue index 2c2fa3a..04f4b42 100644 --- a/src/views/ViewGoalView.vue +++ b/src/views/ViewGoalView.vue @@ -73,13 +73,12 @@ const completeGoal = () => { <div class="flex flex-row flex-wrap items-center justify-center gap-10"> <div class="flex flex-col gap-5 max-w-96"> <button - class="w-min bg-transparent rounded-lg font-bold left-10 cursor-pointer transition-transform duration-200 ease-in-out hover:scale-110 hover:opacity-100 justify-start" - @click="router.push({ name: 'goals', params: { id: goalInstance.id } })" + class="w-min bg-transparent rounded-lg font-bold left-10 cursor-pointer transition-transform duration-200 ease-in-out hover:scale-110 hover:opacity-100 justify-start" + @click="router.push({ name: 'goals', params: { id: goalInstance.id } })" > - 👈Oversikt + 👈Oversikt </button> - <div class="flex flex-col justify-center border-2 rounded-3xl align-middle p-5 card-shadow overflow-hidden w-full" > @@ -91,9 +90,9 @@ const completeGoal = () => { <p class="text-wrap break-words">{{ goalInstance.description }}</p> <div> <img - class="w-20 h-20" - src="https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_1280.png" - alt="Profilbilde" + class="w-20 h-20" + src="https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_1280.png" + alt="Profilbilde" /> </div> </div> @@ -102,7 +101,8 @@ const completeGoal = () => { Du har spart {{ goalInstance.saved }}kr av {{ goalInstance.target }}kr </p> <ProgressBar :completion="completion" /> - <button class="primary secondary mt-6" + <button + class="primary secondary mt-6" v-if="!isCompleted" @click=" router.push({ @@ -124,7 +124,8 @@ const completeGoal = () => { > Slett </button> - <button class="primary mt-4" + <button + class="primary mt-4" v-if="!isCompleted" @click="completeGoal" v-text="'Marker mÃ¥let som ferdig'" -- GitLab