Skip to content

Commit 6d6adeb

Browse files
authored
Merge pull request #53 from meceware/dev
v1.2.2
2 parents c4c8bc5 + 1ad97a2 commit 6d6adeb

File tree

19 files changed

+189
-60
lines changed

19 files changed

+189
-60
lines changed

.github/workflows/docker-build.yml

+5-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ jobs:
2828

2929
- name: Set up Docker Buildx
3030
uses: docker/setup-buildx-action@v3
31+
with:
32+
# Improve network reliability for ARM builds
33+
driver-opts: |
34+
network=host
3135
3236
- name: Log in to GitHub Container Registry
3337
uses: docker/#-action@v3
@@ -58,4 +62,4 @@ jobs:
5862
labels: ${{ steps.meta.outputs.labels }}
5963
cache-from: type=gha
6064
cache-to: type=gha,mode=max
61-
network: host
65+
allow: network.host

src/app/account/account-container.js

+25-9
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,12 @@ const TimezoneManager = ({ user }) => {
6060
try {
6161
setLoading(true);
6262
setSelectedTimezone(value);
63-
await UserUpdateTimezone(value);
64-
toast.success('Timezone updated successfully');
63+
const { success } = await UserUpdateTimezone(value);
64+
if (success) {
65+
toast.success('Timezone updated successfully');
66+
} else {
67+
toast.error('Failed to update timezone');
68+
}
6569
} catch (error) {
6670
toast.error('Failed to update timezone');
6771
} finally {
@@ -85,8 +89,12 @@ const CurrencyManager = ({ user }) => {
8589
try {
8690
setLoading(true);
8791
setSelectedCurrency(currency);
88-
await UserUpdateCurrency(currency);
89-
toast.success('Currency updated successfully');
92+
const { success } = await UserUpdateCurrency(currency);
93+
if (success) {
94+
toast.success('Currency updated successfully');
95+
} else {
96+
toast.error('Failed to update currency');
97+
}
9098
} catch (error) {
9199
toast.error('Failed to update currency');
92100
} finally {
@@ -128,8 +136,12 @@ const NotificationManager = ({user}) => {
128136
setLoading(true);
129137
const validated = SchemaUserNotifications.parse(notifications);
130138
if (!validated) throw new Error('Invalid notifications data');
131-
await UserUpdateNotifications(notifications);
132-
toast.success('Notification preferences saved');
139+
const { success } = await UserUpdateNotifications(notifications);
140+
if (success) {
141+
toast.success('Notification preferences saved');
142+
} else {
143+
toast.error('Failed to save notification preferences');
144+
}
133145
} catch (error) {
134146
toast.error('Failed to save notification preferences');
135147
} finally {
@@ -165,9 +177,13 @@ const UserProfile = ({ user }) => {
165177
if (loading) return;
166178
try {
167179
setLoading(true);
168-
await UserUpdateName(name);
169-
setIsEditing(false);
170-
toast.success('Your name has been updated successfully.');
180+
const { success } = await UserUpdateName(name);
181+
if (success) {
182+
setIsEditing(false);
183+
toast.success('Your name has been updated successfully.');
184+
} else {
185+
toast.error('Failed to update your name!');
186+
}
171187
} catch (error) {
172188
toast.error('Failed to update your name!');
173189
} finally {

src/app/account/actions.js

+28-4
Original file line numberDiff line numberDiff line change
@@ -134,14 +134,20 @@ export const UserUpdateTimezone = async (timezone) => {
134134
throw new Error('Invalid timezone data');
135135
}
136136

137-
return await prisma.user.update({
137+
const updated = await prisma.user.update({
138138
where: {
139139
id: session.user.id,
140140
},
141141
data: {
142142
timezone: validatedData,
143143
}
144144
});
145+
146+
if (!updated) {
147+
return { success: false, timezone: validatedData };
148+
}
149+
150+
return { success: true, timezone: updated.timezone };
145151
};
146152

147153
export const UserUpdateCurrency = async (currency) => {
@@ -155,14 +161,20 @@ export const UserUpdateCurrency = async (currency) => {
155161
throw new Error('Invalid currency data');
156162
}
157163

158-
return await prisma.user.update({
164+
const updated = await prisma.user.update({
159165
where: {
160166
id: session.user.id,
161167
},
162168
data: {
163169
currency: validatedData,
164170
}
165171
});
172+
173+
if (!updated) {
174+
return { success: false, currency: validatedData };
175+
}
176+
177+
return { success: true, currency: updated.currency };
166178
};
167179

168180
export const UserUpdateNotifications = async (notifications) => {
@@ -176,7 +188,7 @@ export const UserUpdateNotifications = async (notifications) => {
176188
throw new Error('Invalid notifications data');
177189
}
178190

179-
return await prisma.user.update({
191+
const updated = await prisma.user.update({
180192
where: {
181193
id: session.user.id,
182194
},
@@ -192,6 +204,12 @@ export const UserUpdateNotifications = async (notifications) => {
192204
}),
193205
}
194206
});
207+
208+
if (!updated) {
209+
return { success: false, notifications: validatedData };
210+
}
211+
212+
return { success: true, notifications: updated.notifications };
195213
};
196214

197215
export const UserUpdateName = async (name) => {
@@ -205,14 +223,20 @@ export const UserUpdateName = async (name) => {
205223
throw new Error('Invalid name data');
206224
}
207225

208-
return await prisma.user.update({
226+
const updated = await prisma.user.update({
209227
where: {
210228
id: session.user.id,
211229
},
212230
data: {
213231
name: validatedData,
214232
}
215233
});
234+
235+
if (!updated) {
236+
return { success: false, name: validatedData };
237+
}
238+
239+
return { success: true, name: updated.name };
216240
};
217241

218242
export const UserExportData = async () => {

src/app/account/page.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { paddleGetStatus } from '@/lib/paddle/status';
88
import { paddleGetSession } from '@/lib/paddle/status';
99

1010
const PageAccount = async () => {
11-
const { userWithoutId, paddleStatus } = await paddleGetSession();
11+
const { user, paddleStatus } = await paddleGetSession();
1212

1313
// const paddleCustomer = await paddleGetCustomer(user.id);
1414
// console.log('paddleCustomer', paddleCustomer);
@@ -20,7 +20,7 @@ const PageAccount = async () => {
2020
return (
2121
<div className='container flex flex-col items-center justify-center gap-6 text-center'>
2222
<AccountSettings
23-
user={userWithoutId}
23+
user={user}
2424
paddleStatus={paddleStatus}
2525
/>
2626
</div>

src/app/edit/[slug]/page.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ import { SubscriptionGuard } from '@/components/subscription-guard';
1010

1111
const PageSubscriptionEdit = async ({ params }) => {
1212
const slug = (await params).slug;
13-
const { user, userWithoutId, paddleStatus } = await paddleGetSession();
13+
const { session, user, paddleStatus } = await paddleGetSession();
1414

15-
const subscription = await SubscriptionGet(slug, user.id);
15+
const subscription = await SubscriptionGet(slug, session?.user?.id);
1616
if (!subscription) {
1717
return notFound();
1818
}
@@ -24,7 +24,7 @@ const PageSubscriptionEdit = async ({ params }) => {
2424
return (
2525
<SubscriptionGuard paddleStatus={paddleStatus}>
2626
<div className='container flex flex-col items-center justify-center gap-6 text-center'>
27-
<SubscriptionEdit user={userWithoutId} subscription={ subscription } />
27+
<SubscriptionEdit user={user} subscription={ subscription } />
2828
</div>
2929
</SubscriptionGuard>
3030
)

src/app/edit/new/page.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ import { paddleGetSession } from '@/lib/paddle/status';
66
import { SubscriptionGuard } from '@/components/subscription-guard';
77

88
const PageNewSubscription = async () => {
9-
const { userWithoutId, paddleStatus } = await paddleGetSession();
9+
const { user, paddleStatus } = await paddleGetSession();
1010

1111
return (
1212
<SubscriptionGuard paddleStatus={paddleStatus}>
1313
<div className='container flex flex-col items-center justify-center gap-6 text-center'>
14-
<SubscriptionEdit user={userWithoutId} />
14+
<SubscriptionEdit user={user} />
1515
</div>
1616
</SubscriptionGuard>
1717
)

src/app/layout.js

+68
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,80 @@ export const viewport = {
9090
initialScale: 1,
9191
};
9292

93+
const jsonLd = {
94+
'@context': 'https://schema.org',
95+
'@type': 'SoftwareApplication',
96+
'@id': `${siteConfig.url}/#software`,
97+
'name': siteConfig.name,
98+
'description': siteConfig.description,
99+
'applicationCategory': 'FinanceApplication',
100+
'operatingSystem': 'Web',
101+
'url': siteConfig.url,
102+
'offers': [
103+
{
104+
'@type': 'Offer',
105+
'name': 'Premium Plan',
106+
'category': 'SubscriptionPlan',
107+
'price': '1.50',
108+
'priceCurrency': 'EUR',
109+
'availability': 'https://schema.org/InStock',
110+
'priceValidUntil': `${(new Date()).getFullYear()}-12-31`,
111+
'seller': {
112+
'@type': 'Organization',
113+
'name': siteConfig.author.name,
114+
'url': siteConfig.author.url
115+
}
116+
},
117+
{
118+
'@type': 'Offer',
119+
'name': 'Self-Hosted Edition',
120+
'price': '0',
121+
'priceCurrency': 'EUR',
122+
'availability': 'https://schema.org/InStock',
123+
'seller': {
124+
'@type': 'Organization',
125+
'name': siteConfig.author.name,
126+
'url': siteConfig.author.url
127+
}
128+
}
129+
],
130+
'featureList': [
131+
'Subscription tracking',
132+
'Payment reminders',
133+
'Multi-currency support',
134+
'Expense analytics',
135+
'Timezone support',
136+
'Push notifications',
137+
'Email notifications',
138+
],
139+
'screenshot': `${siteConfig.url}/images/og.png`,
140+
'softwareVersion': '1.0',
141+
'datePublished': '2025-02-25',
142+
'keywords': siteConfig.keywords,
143+
'author': {
144+
'@type': 'Organization',
145+
'name': siteConfig.author.name,
146+
'url': siteConfig.author.url
147+
},
148+
'provider': {
149+
'@type': 'Organization',
150+
'name': siteConfig.author.name,
151+
'url': siteConfig.author.url
152+
}
153+
};
154+
93155
// Root Layout
94156
export default async function RootLayout({ children }) {
95157
const session = await auth();
96158

97159
return (
98160
<html lang='en' suppressHydrationWarning>
161+
<head>
162+
<script
163+
type='application/ld+json'
164+
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
165+
/>
166+
</head>
99167
<body className={`${inter.className} antialiased`}>
100168
<SessionProvider session={session}>
101169
<ThemeProvider attribute='class' defaultTheme='system' enableSystem disableTransitionOnChange>

src/app/reports/page.js

+11-4
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,28 @@ import { paddleGetSession } from '@/lib/paddle/status';
77
import { SubscriptionGuard } from '@/components/subscription-guard';
88

99
const PageReports = async () => {
10-
const { user, paddleStatus } = await paddleGetSession();
10+
const { session, paddleStatus } = await paddleGetSession();
1111

1212
const subscriptions = await prisma.subscription.findMany({
1313
where: {
14-
userId: user.id,
14+
userId: session?.user?.id,
1515
},
1616
include: {
1717
categories: {
1818
select: {
19-
id: true,
2019
name: true,
2120
color: true
2221
}
2322
}
2423
},
24+
omit: {
25+
userId: true,
26+
createdAt: true,
27+
updatedAt: true,
28+
nextNotificationTime: true,
29+
nextNotificationDetails: true,
30+
notes: true,
31+
},
2532
orderBy: {
2633
paymentDate: 'asc'
2734
}
@@ -30,7 +37,7 @@ const PageReports = async () => {
3037
return (
3138
<SubscriptionGuard paddleStatus={paddleStatus}>
3239
<div className='flex flex-col items-center w-full max-w-3xl gap-4'>
33-
<SubscriptionReports subscriptions={ subscriptions?.map(({ userId, ...rest }) => rest) } />
40+
<SubscriptionReports subscriptions={subscriptions} />
3441
</div>
3542
</SubscriptionGuard>
3643
)

src/app/robots.js

-4
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,8 @@ export default function robots() {
77
allow: '/',
88
disallow: [
99
'/account',
10-
'/api',
1110
'/api/*',
12-
'/edit',
13-
'/edit/new',
1411
'/edit/*',
15-
'/#',
1612
'/reports',
1713
'/signout',
1814
],

src/components/cookie-consent.js

+3
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ export function CookieConsent() {
7575
<Checkbox
7676
checked={preferences.essential}
7777
disabled={true}
78+
title='Essential Cookies'
7879
/>
7980
<div className='grid gap-1.5 leading-none'>
8081
<label className='font-medium'>
@@ -94,6 +95,7 @@ export function CookieConsent() {
9495
onCheckedChange={(checked) =>
9596
setPreferences(prev => ({ ...prev, functional: checked === true }))
9697
}
98+
title='Functional Cookies'
9799
/>
98100
<div className='grid gap-1.5 leading-none'>
99101
<label className='font-medium'>
@@ -113,6 +115,7 @@ export function CookieConsent() {
113115
onCheckedChange={(checked) =>
114116
setPreferences(prev => ({ ...prev, analytics: checked === true }))
115117
}
118+
title='Analytics Cookies'
116119
/>
117120
<div className='grid gap-1.5 leading-none'>
118121
<label className='font-medium'>

src/components/header.js

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export default function Header({ mainNavigation = (<></>), iconNavigation = (<><
3939
alt='Description of the image'
4040
width={32}
4141
height={32}
42+
priority
4243
/>
4344
<div className='inline-flex gap-0 justify-center items-end'>
4445
<span className='font-semibold text-xl'>Wapy</span>

0 commit comments

Comments
 (0)