Skip to content

Commit 78de34c

Browse files
authored
feat: update agreement action (#16)
* feat: update agreement action * chore: some fixes
1 parent 702727a commit 78de34c

15 files changed

Lines changed: 1410 additions & 482 deletions

File tree

apps/web-app/app/components/PartnerAgreementCard.vue

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
<template>
2-
<UCard
3-
v-if="agreement"
4-
variant="subtle"
5-
class="h-full"
6-
>
2+
<UCard class="h-full" @click="modalUpdatePartnerAgreement.open({ agreementId: agreement.id })">
73
<div class="flex flex-col gap-3">
84
<div class="flex flex-row items-start gap-3.5">
95
<UIcon name="i-lucide-scroll-text" class="shrink-0 size-16 text-secondary" />
@@ -45,24 +41,18 @@
4541
</p>
4642
</div>
4743
</UCard>
48-
<CreateCard
49-
v-else
50-
label="Добавить договор"
51-
icon="i-lucide-scroll-text"
52-
@click="modalCreatePartnerAgreement.open({ partnerId, legalEntityId })"
53-
/>
5444
</template>
5545

5646
<script setup lang="ts">
5747
import type { PartnerAgreement } from '@roll-stack/database'
58-
import { ModalCreatePartnerAgreement } from '#components'
48+
import { ModalUpdatePartnerAgreement } from '#components'
5949
import { format } from 'date-fns'
6050
import { ru } from 'date-fns/locale/ru'
6151
62-
const { agreement } = defineProps<{ partnerId: string, legalEntityId: string, agreement: PartnerAgreement | null | undefined }>()
52+
const { agreement } = defineProps<{ agreement: PartnerAgreement }>()
6353
6454
const overlay = useOverlay()
65-
const modalCreatePartnerAgreement = overlay.create(ModalCreatePartnerAgreement)
55+
const modalUpdatePartnerAgreement = overlay.create(ModalUpdatePartnerAgreement)
6656
6757
const agreementProgress = computed(() => {
6858
if (!agreement?.willEndAt || !agreement?.concludedAt) {
@@ -73,6 +63,8 @@ const agreementProgress = computed(() => {
7363
const concludedAt = new Date(agreement.concludedAt)
7464
const willEndAt = new Date(agreement.willEndAt)
7565
76-
return Math.floor(100 - ((now.getTime() - concludedAt.getTime()) / (willEndAt.getTime() - concludedAt.getTime())) * 100)
66+
const res = Math.floor(100 - ((now.getTime() - concludedAt.getTime()) / (willEndAt.getTime() - concludedAt.getTime())) * 100)
67+
68+
return res > 0 ? res : 0
7769
})
7870
</script>

apps/web-app/app/components/PartnerCard.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ const agreementProgress = computed(() => {
7777
const concludedAt = new Date(partner.activeAgreement.concludedAt)
7878
const willEndAt = new Date(partner.activeAgreement.willEndAt)
7979
80-
return Math.floor(100 - ((now.getTime() - concludedAt.getTime()) / (willEndAt.getTime() - concludedAt.getTime())) * 100)
80+
const res = Math.floor(100 - ((now.getTime() - concludedAt.getTime()) / (willEndAt.getTime() - concludedAt.getTime())) * 100)
81+
82+
return res > 0 ? res : 0
8183
})
8284
</script>

apps/web-app/app/components/form/CreatePartnerAgreement.vue

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<template>
22
<UForm
3+
ref="form"
34
:validate="createValidator(createPartnerAgreementSchema)"
45
:state="state"
56
class="flex flex-col gap-3"
@@ -29,7 +30,6 @@
2930
<UFormField
3031
label="Дата окончания"
3132
name="willEndAt"
32-
required
3333
>
3434
<UInput
3535
:value="selectedWillEndAt ? df.format(selectedWillEndAt.toDate(getLocalTimeZone())) : ''"
@@ -45,15 +45,23 @@
4545
</template>
4646
</UPopover>
4747

48-
<UFormField label="Номер договора (внутренний)" name="internalId">
48+
<UFormField
49+
label="Номер договора (внутренний)"
50+
name="internalId"
51+
required
52+
>
4953
<UInput
5054
v-model="state.internalId"
5155
size="xl"
5256
class="w-full items-center justify-center"
5357
/>
5458
</UFormField>
5559

56-
<UFormField label="Роялти, %" name="royalty">
60+
<UFormField
61+
label="Роялти, %"
62+
name="royalty"
63+
required
64+
>
5765
<UInputNumber
5866
v-model="state.royalty"
5967
orientation="vertical"
@@ -63,7 +71,11 @@
6371
/>
6472
</UFormField>
6573

66-
<UFormField label="Мин. роялти, руб" name="minRoyaltyPerMonth">
74+
<UFormField
75+
label="Мин. роялти, руб"
76+
name="minRoyaltyPerMonth"
77+
required
78+
>
6779
<UInputNumber
6880
v-model="state.minRoyaltyPerMonth"
6981
orientation="vertical"
@@ -72,7 +84,11 @@
7284
/>
7385
</UFormField>
7486

75-
<UFormField label="Паушальный взнос, руб" name="lumpSumPayment">
87+
<UFormField
88+
label="Паушальный взнос, руб"
89+
name="lumpSumPayment"
90+
required
91+
>
7692
<UInputNumber
7793
v-model="state.lumpSumPayment"
7894
orientation="vertical"
@@ -117,6 +133,8 @@ const actionToast = useActionToast()
117133
118134
const partnerStore = usePartnerStore()
119135
136+
const form = useTemplateRef('form')
137+
120138
const state = ref<Partial<CreatePartnerAgreement>>({
121139
concludedAt: undefined,
122140
willEndAt: undefined,
@@ -139,11 +157,15 @@ watch(selectedConcludedAt, () => {
139157
state.value.concludedAt = new Date(
140158
`${selectedConcludedAt.value?.toString()} 12:00:00`,
141159
).toISOString()
160+
161+
form.value?.clear()
142162
})
143163
watch(selectedWillEndAt, () => {
144164
state.value.willEndAt = new Date(
145165
`${selectedWillEndAt.value?.toString()} 12:00:00`,
146166
).toISOString()
167+
168+
form.value?.clear()
147169
})
148170
149171
async function onSubmit(event: FormSubmitEvent<CreatePartnerAgreement>) {
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
<template>
2+
<UForm
3+
:validate="createValidator(updatePartnerAgreementSchema)"
4+
:state="state"
5+
class="flex flex-col gap-3"
6+
@submit="onSubmit"
7+
>
8+
<UFormField label="Роялти, %" name="royalty">
9+
<UInputNumber
10+
v-model="state.royalty"
11+
orientation="vertical"
12+
:step="0.1"
13+
size="xl"
14+
class="w-full items-center justify-center"
15+
/>
16+
</UFormField>
17+
18+
<UFormField label="Мин. роялти, руб" name="minRoyaltyPerMonth">
19+
<UInputNumber
20+
v-model="state.minRoyaltyPerMonth"
21+
orientation="vertical"
22+
size="xl"
23+
class="w-full items-center justify-center"
24+
/>
25+
</UFormField>
26+
27+
<UFormField label="Маркетинговый сбор, %" name="marketingFee">
28+
<UInputNumber
29+
v-model="state.marketingFee"
30+
orientation="vertical"
31+
size="xl"
32+
class="w-full items-center justify-center"
33+
/>
34+
</UFormField>
35+
36+
<UFormField label="Мин. маркетинговый сбор, руб" name="minMarketingFeePerMonth">
37+
<UInputNumber
38+
v-model="state.minMarketingFeePerMonth"
39+
orientation="vertical"
40+
size="xl"
41+
class="w-full items-center justify-center"
42+
/>
43+
</UFormField>
44+
45+
<UFormField label="Паушальный взнос, руб" name="lumpSumPayment">
46+
<UInputNumber
47+
v-model="state.lumpSumPayment"
48+
orientation="vertical"
49+
size="xl"
50+
class="w-full items-center justify-center"
51+
/>
52+
</UFormField>
53+
54+
<UFormField :label="$t('common.comment')" name="comment">
55+
<UInput
56+
v-model="state.comment"
57+
size="xl"
58+
placeholder="Для внутреннего использования"
59+
class="w-full items-center justify-center"
60+
/>
61+
</UFormField>
62+
63+
<UButton
64+
type="submit"
65+
variant="solid"
66+
color="secondary"
67+
size="xl"
68+
block
69+
class="mt-3"
70+
:label="$t('common.update')"
71+
/>
72+
</UForm>
73+
</template>
74+
75+
<script setup lang="ts">
76+
import type { UpdatePartnerAgreement } from '#shared/services/partner'
77+
import type { FormSubmitEvent } from '@nuxt/ui'
78+
import { updatePartnerAgreementSchema } from '#shared/services/partner'
79+
80+
const { agreementId } = defineProps<{
81+
agreementId: string
82+
}>()
83+
84+
const emit = defineEmits(['success', 'submitted'])
85+
86+
const { t } = useI18n()
87+
const actionToast = useActionToast()
88+
89+
const partnerStore = usePartnerStore()
90+
const partner = computed(() => partnerStore.partners.find((partner) => partner.activeAgreementId === agreementId))
91+
const agreement = computed(() => partner.value?.activeAgreement)
92+
93+
const state = ref<Partial<UpdatePartnerAgreement>>({
94+
royalty: agreement.value?.royalty,
95+
minRoyaltyPerMonth: agreement.value?.minRoyaltyPerMonth,
96+
marketingFee: agreement.value?.marketingFee,
97+
minMarketingFeePerMonth: agreement.value?.minMarketingFeePerMonth,
98+
lumpSumPayment: agreement.value?.lumpSumPayment,
99+
comment: agreement.value?.comment ?? undefined,
100+
})
101+
102+
async function onSubmit(event: FormSubmitEvent<UpdatePartnerAgreement>) {
103+
const toastId = actionToast.start()
104+
emit('submitted')
105+
106+
try {
107+
await $fetch(`/api/partner/agreement/id/${agreementId}`, {
108+
method: 'PATCH',
109+
body: event.data,
110+
})
111+
112+
await partnerStore.update()
113+
114+
actionToast.success(toastId, t('toast.partner-agreement-updated'))
115+
emit('success')
116+
} catch (error) {
117+
console.error(error)
118+
actionToast.error(toastId)
119+
}
120+
}
121+
</script>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<template>
2+
<UModal title="Обновление договора">
3+
<template #body>
4+
<FormUpdatePartnerAgreement
5+
:agreement-id="agreementId"
6+
@submitted="overlay.closeAll"
7+
@success="overlay.closeAll"
8+
/>
9+
</template>
10+
</UModal>
11+
</template>
12+
13+
<script setup lang="ts">
14+
defineProps<{
15+
agreementId: string
16+
}>()
17+
18+
const overlay = useOverlay()
19+
</script>

apps/web-app/app/pages/partner/[id].vue

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,39 @@
77
class="flex-1 -ml-2.5"
88
/>
99

10-
<UButton
10+
<!-- <UButton
1111
size="lg"
1212
variant="solid"
1313
color="secondary"
1414
class="w-full md:w-fit"
1515
icon="i-lucide-square-pen"
1616
:label="t('common.edit')"
1717
@click="() => {}"
18-
/>
18+
/> -->
1919
</template>
2020
</Header>
2121

2222
<NuxtPage />
2323
</template>
2424

2525
<script setup lang="ts">
26+
import { format } from 'date-fns'
27+
import { ru } from 'date-fns/locale/ru'
28+
2629
const { t } = useI18n()
2730
const { params } = useRoute('partner-id')
2831
2932
const partnerStore = usePartnerStore()
3033
const partner = computed(() => partnerStore.partners.find((partner) => partner.id === params.id))
3134
35+
const activeAgreementTo = computed(() => {
36+
if (!partner.value?.activeAgreement?.willEndAt) {
37+
return 'отсутствует'
38+
}
39+
40+
return `до ${format(new Date(partner.value?.activeAgreement?.willEndAt), 'd MMMM yyyy', { locale: ru })}`
41+
})
42+
3243
const submenuItems = computed(() => [
3344
{
3445
label: t('common.partner'),
@@ -42,6 +53,17 @@ const submenuItems = computed(() => [
4253
icon: 'i-lucide-map-pinned',
4354
badge: partner.value?.kitchens.length,
4455
},
56+
{
57+
label: 'Договор',
58+
to: `/partner/${partner.value?.id}/agreement`,
59+
icon: 'i-lucide-scroll-text',
60+
badge: activeAgreementTo.value,
61+
},
62+
{
63+
label: 'Юр. лицо',
64+
to: `/partner/${partner.value?.id}/legal`,
65+
icon: 'i-lucide-scale',
66+
},
4567
])
4668
4769
useHead({
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<template>
2+
<Content>
3+
<div class="grid grid-cols-1 gap-4 md:gap-6 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
4+
<div v-if="partner?.activeAgreement" class="lg:col-span-2">
5+
<PartnerAgreementCard :agreement="partner.activeAgreement" />
6+
</div>
7+
8+
<div>
9+
<CreateCard
10+
label="Добавить новый договор"
11+
icon="i-lucide-scroll-text"
12+
@click="modalCreatePartnerAgreement.open({ partnerId: partner?.id, legalEntityId: partner?.legalEntity?.id })"
13+
/>
14+
</div>
15+
</div>
16+
</Content>
17+
</template>
18+
19+
<script setup lang="ts">
20+
import { ModalCreatePartnerAgreement } from '#components'
21+
22+
const { t } = useI18n()
23+
const { params } = useRoute('partner-id')
24+
25+
const partnerStore = usePartnerStore()
26+
const partner = computed(() => partnerStore.partners.find((partner) => partner.id === params.id))
27+
28+
const overlay = useOverlay()
29+
const modalCreatePartnerAgreement = overlay.create(ModalCreatePartnerAgreement)
30+
31+
useHead({
32+
title: t('app.partner-agreement.title'),
33+
})
34+
</script>

0 commit comments

Comments
 (0)