Skip to content

Commit cc22a7f

Browse files
committed
refactor(subscriptions): fix appearce icon, enchance form, refactor and update db schema
1 parent 1d7703d commit cc22a7f

File tree

16 files changed

+131
-74
lines changed

16 files changed

+131
-74
lines changed

apps/api/src/api/v1/controllers/subscription.controller.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export class SubscriptionController {
1818
req.file,
1919
`${req.user.id}/subscription/${parsedSubscription.title}`
2020
)
21-
parsedSubscription.icon = filePath
21+
parsedSubscription.appearance_logo_icon = filePath
2222
}
2323

2424
const subscription = await prisma.subscriptions.create({
@@ -52,7 +52,7 @@ export class SubscriptionController {
5252
req.file,
5353
`${req.user.id}/subscription/${parsedSubscription.title}`
5454
)
55-
parsedSubscription.icon = filePath
55+
parsedSubscription.appearance_logo_icon = filePath
5656
}
5757

5858
const subscription = await prisma.subscriptions.update({

apps/app/app/(admin)/subscriptions/view.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,8 @@ export default function SubscriptionsView() {
146146
<div className='flex flex-col items-center space-y-8 justify-center h-[300px]'>
147147
<Landmark />
148148
<div className='flex flex-col items-center space-y-2 justify-center'>
149-
<h4>{t('bankAccounts.empty.title')}</h4>
150-
<p>{t('bankAccounts.empty.subtitle')}</p>
149+
<h4>{t('subscriptions.empty.title')}</h4>
150+
<p>{t('subscriptions.empty.subtitle')}</p>
151151
</div>
152152
</div>
153153
)}
@@ -156,7 +156,7 @@ export default function SubscriptionsView() {
156156
{itemToDelete && (
157157
<DeleteModal
158158
title={itemToDelete.title}
159-
description={t('bankAccounts.modal.deleteDescription')}
159+
description={t('subscriptions.modal.deleteDescription')}
160160
open={true}
161161
closeDialog={() => setItemToDelete(null)}
162162
loading={loading}

apps/app/components/dialog/BankAccountDialog.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useTranslations } from 'next-intl'
22
import { Modal } from '../modal/form'
33
import { useRef, useState } from 'react'
4-
import { IBankAccount } from '@poveroh/types'
4+
import { AppearanceMode, IBankAccount } from '@poveroh/types'
55
import { toast } from '@poveroh/ui/components/sonner'
66
import { useBankAccount } from '@/hooks/useBankAccount'
77
import { BankAccountForm } from '../form/BankAccountForm'
@@ -67,7 +67,7 @@ export function BankAccountDialog(props: DialogProps) {
6767
open={props.open}
6868
title={title}
6969
icon={props.initialData?.logo_icon}
70-
iconMode='icon'
70+
iconMode={AppearanceMode.ICON}
7171
handleOpenChange={props.closeDialog}
7272
loading={loading}
7373
inEditingMode={props.inEditingMode}

apps/app/components/dialog/CategoryDialog.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useRef, useState } from 'react'
22
import { useTranslations } from 'next-intl'
33
import { toast } from '@poveroh/ui/components/sonner'
4-
import { ICategory } from '@poveroh/types'
4+
import { AppearanceMode, ICategory } from '@poveroh/types'
55
import { Modal } from '../modal/form'
66
import { CategoryForm } from '../form/CategoryForm'
77
import { useCategory } from '@/hooks/useCategory'
@@ -68,7 +68,7 @@ export function CategoryDialog(props: DialogProps) {
6868
open={props.open}
6969
title={title}
7070
icon={props.initialData?.logo_icon}
71-
iconMode='icon'
71+
iconMode={AppearanceMode.ICON}
7272
handleOpenChange={props.closeDialog}
7373
loading={loading}
7474
inEditingMode={props.inEditingMode}

apps/app/components/dialog/SubcategoryDialog.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useRef, useState } from 'react'
22
import { useTranslations } from 'next-intl'
33
import { toast } from '@poveroh/ui/components/sonner'
4-
import { ISubcategory } from '@poveroh/types'
4+
import { AppearanceMode, ISubcategory } from '@poveroh/types'
55
import { Modal } from '../modal/form'
66
import { SubcategoryForm } from '../form/SubcategoryForm'
77
import { useCategory } from '@/hooks/useCategory'
@@ -67,7 +67,7 @@ export function SubcategoryDialog(props: DialogProps) {
6767
open={props.open}
6868
title={title}
6969
icon={props.initialData?.logo_icon}
70-
iconMode='icon'
70+
iconMode={AppearanceMode.ICON}
7171
handleOpenChange={props.closeDialog}
7272
loading={loading}
7373
inEditingMode={props.inEditingMode}

apps/app/components/dialog/SubscriptionDialog.tsx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import { useTranslations } from 'next-intl'
22
import { Modal } from '../modal/form'
33
import { useRef, useState } from 'react'
4-
import { Currencies, CyclePeriod, IBrand, ISubscription, RememberPeriod } from '@poveroh/types'
4+
import { AppearanceMode, Currencies, CyclePeriod, IBrand, ISubscription, RememberPeriod } from '@poveroh/types'
55
import { toast } from '@poveroh/ui/components/sonner'
66
import { useSubscriptions } from '@/hooks/useSubscriptions'
77
import { SubscriptionForm } from '../form/SubscriptionsForm'
88
import { SubscriptionsSelector } from '../form/SubscriptionsSelector'
99
import { Button } from '@poveroh/ui/components/button'
1010
import { DialogFooter } from '@poveroh/ui/components/dialog'
11-
import { iconList } from '../icon'
1211

1312
type DialogProps = {
1413
open: boolean
@@ -79,8 +78,8 @@ export function SubscriptionDialog(props: DialogProps) {
7978
description: '',
8079
amount: 0,
8180
currency: Currencies.USD,
82-
logo: brand.logo,
83-
icon: iconList[0] as string,
81+
appearance_mode: AppearanceMode.LOGO,
82+
appearance_logo_icon: brand.logo,
8483
first_payment: new Date().toISOString(),
8584
cycle_number: '1',
8685
cycle_period: CyclePeriod.MONTH,
@@ -97,8 +96,8 @@ export function SubscriptionDialog(props: DialogProps) {
9796
<Modal
9897
open={props.open}
9998
title={title}
100-
icon={localSubscription?.logo}
101-
iconMode='img'
99+
icon={localSubscription?.appearance_logo_icon}
100+
iconMode={localSubscription?.appearance_mode}
102101
iconCircled={true}
103102
handleOpenChange={props.closeDialog}
104103
loading={loading}

apps/app/components/form/SubscriptionsForm.tsx

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { z } from 'zod'
66
import { zodResolver } from '@hookform/resolvers/zod'
77
import { useTranslations } from 'next-intl'
88

9-
import { Currencies, CyclePeriod, ISubscription, RememberPeriod } from '@poveroh/types'
9+
import { AppearanceMode, Currencies, CyclePeriod, ISubscription, RememberPeriod } from '@poveroh/types'
1010

1111
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@poveroh/ui/components/form'
1212
import { Input } from '@poveroh/ui/components/input'
@@ -42,28 +42,41 @@ export const SubscriptionForm = forwardRef(
4242
description: '',
4343
amount: 0,
4444
currency: Currencies.EUR,
45-
logo: '',
46-
icon: iconList[0] as string,
45+
appearance_mode: AppearanceMode.ICON,
46+
appearance_logo_icon: iconList[0] as string,
4747
first_payment: new Date().toISOString().split('T')[0],
4848
cycle_number: '1',
4949
cycle_period: CyclePeriod.MONTH,
5050
remember_period: RememberPeriod.THREE_DAYS,
5151
bank_account_id: ''
5252
}
5353

54-
const formSchema = z.object({
55-
title: z.string().nonempty(t('messages.errors.required')),
56-
description: z.string().optional(),
57-
amount: z.number().min(0),
58-
currency: z.nativeEnum(Currencies),
59-
logo: z.string().url().optional().or(z.literal('')),
60-
icon: z.string(),
61-
first_payment: z.string(),
62-
cycle_number: z.string(),
63-
cycle_period: z.nativeEnum(CyclePeriod),
64-
remember_period: z.nativeEnum(RememberPeriod).optional(),
65-
bank_account_id: z.string().nonempty(t('messages.errors.required'))
66-
})
54+
const formSchema = z
55+
.object({
56+
title: z.string().nonempty(t('messages.errors.required')),
57+
description: z.string().optional(),
58+
amount: z.number().min(0),
59+
currency: z.nativeEnum(Currencies),
60+
appearance_mode: z.nativeEnum(AppearanceMode),
61+
appearance_logo_icon: z.string().nonempty(t('messages.errors.required')),
62+
first_payment: z.string(),
63+
cycle_number: z.string(),
64+
cycle_period: z.nativeEnum(CyclePeriod),
65+
remember_period: z.nativeEnum(RememberPeriod).optional(),
66+
bank_account_id: z.string().nonempty(t('messages.errors.required'))
67+
})
68+
.refine(
69+
data => {
70+
if (data.appearance_mode === AppearanceMode.LOGO) {
71+
return z.string().safeParse(data.appearance_logo_icon).success
72+
}
73+
return true
74+
},
75+
{
76+
message: t('messages.errors.url'),
77+
path: ['appearance_logo_icon']
78+
}
79+
)
6780

6881
const form = useForm<z.infer<typeof formSchema>>({
6982
resolver: zodResolver(formSchema),
@@ -77,8 +90,8 @@ export const SubscriptionForm = forwardRef(
7790
}))
7891

7992
useEffect(() => {
80-
console.debug('Form errors:', form.formState.errors)
81-
}, [form.formState.errors])
93+
console.log(!fromTemplate)
94+
})
8295

8396
const handleLocalSubmit = async (values: z.infer<typeof formSchema>) => {
8497
try {
@@ -258,7 +271,7 @@ export const SubscriptionForm = forwardRef(
258271
)}
259272
/>
260273

261-
{!fromTemplate && (
274+
{(!fromTemplate || initialData?.appearance_mode == AppearanceMode.ICON) && (
262275
<div className='flex flex-col space-y-4'>
263276
<FormItem>
264277
<FormLabel mandatory={!inEditingMode}>{t('form.icon.label')}</FormLabel>
@@ -275,7 +288,7 @@ export const SubscriptionForm = forwardRef(
275288
className={`box-border p-1 cursor-pointer flex justify-center items-center rounded-md h-[30px] w-[30px]
276289
${icon === x ? 'bg-white text-black border border-hr' : ''}`}
277290
onClick={() => {
278-
form.setValue('icon', x)
291+
form.setValue('appearance_logo_icon', x)
279292
setIcon(x)
280293
}}
281294
>

apps/app/components/item/SubscriptionsItem.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { BrandIcon } from '../icon/BrandIcon'
2-
import { IBankAccount, ISubscription } from '@poveroh/types'
2+
import { AppearanceMode, IBankAccount, ISubscription } from '@poveroh/types'
33
import { OptionsPopover } from '../navbar/OptionsPopoverr'
44
import DynamicIcon from '../icon/DynamicIcon'
55
import icons from 'currency-icons'
@@ -33,10 +33,15 @@ export function SubscriptionItem({ subscription, openDelete, openEdit }: Subscri
3333
<div className='flex flex-row items-center space-x-5'>
3434
<div className='flex items-center justify-center h-[40px] w-[40px]'>
3535
{(() => {
36-
if (subscription.logo) {
37-
return <BrandIcon icon={subscription.logo} />
36+
if (subscription.appearance_mode == AppearanceMode.LOGO) {
37+
return <BrandIcon circled icon={subscription.appearance_logo_icon} />
3838
} else {
39-
return <DynamicIcon name={subscription?.icon || 'landmark'} className='h-[30px] w-[30px]' />
39+
return (
40+
<DynamicIcon
41+
name={subscription?.appearance_logo_icon || 'landmark'}
42+
className='h-[30px] w-[30px]'
43+
/>
44+
)
4045
}
4146
})()}
4247
</div>

apps/app/components/modal/form.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@ import PerfectScrollbar from 'react-perfect-scrollbar'
88
import 'react-perfect-scrollbar/dist/css/styles.css'
99
import { cn } from '@poveroh/ui/lib/utils'
1010
import { ReactElement } from 'react'
11+
import { AppearanceMode } from '@poveroh/types'
1112

1213
type ModalProps = {
1314
open: boolean
1415
title: string
1516
description?: string
1617
icon?: string
17-
iconMode?: 'icon' | 'img'
18+
iconMode?: AppearanceMode
1819
iconCircled?: boolean
1920
children: React.ReactNode
2021
showFooter?: boolean
@@ -31,7 +32,7 @@ export function Modal({ showFooter = true, ...props }: ModalProps) {
3132
<DialogHeader>
3233
<div className='flex flex-row items-center space-x-3'>
3334
{props.icon &&
34-
(props.iconMode === 'img' ? (
35+
(props.iconMode === AppearanceMode.LOGO ? (
3536
<BrandIcon circled={props.iconCircled} icon={props.icon} size='xl'></BrandIcon>
3637
) : (
3738
<DynamicIcon key={props.icon} name={props.icon} />

apps/app/hooks/useSubscriptions.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,12 @@ export const useSubscriptions = () => {
6464
}
6565
}
6666

67-
const getNextExecutionText = (
68-
subscription: ISubscription,
69-
fromDate: Date = new Date() // 🆕 now is configurable
70-
) => {
67+
const getNextExecutionText = (subscription: ISubscription, fromDate: Date = new Date()) => {
7168
const now = fromDate
7269
let next = new Date(subscription.first_payment)
7370

7471
const cycle_number = Number(subscription.cycle_number)
75-
// Ensure next is in the future
72+
7673
while (next < now) {
7774
switch (subscription.cycle_period) {
7875
case CyclePeriod.DAY:

0 commit comments

Comments
 (0)