Refactored frontend directory
Some checks failed
Chore App Build, Test, and Push Docker Images / build-and-push (push) Failing after 2m46s

This commit is contained in:
2026-04-25 00:40:15 -04:00
parent db846f4e31
commit 127378797c
263 changed files with 88 additions and 79 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
frontend/public/edit.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

BIN
frontend/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

View File

@@ -0,0 +1,29 @@
{
"id": "/",
"name": "Chorly",
"short_name": "Chorly",
"start_url": "/",
"display": "standalone",
"theme_color": "#4a90e2",
"background_color": "#ffffff",
"description": "Track chores and rewards for your family",
"icons": [
{
"src": "/favicon.ico",
"sizes": "32x32",
"type": "image/x-icon"
},
{
"src": "/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any"
},
{
"src": "/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
frontend/public/profile.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

122
frontend/public/sw.js Normal file
View File

@@ -0,0 +1,122 @@
/* Service Worker for Reward App push notifications */
/* Activate immediately — no waiting for old tabs to close */
self.addEventListener('install', function (event) {
event.waitUntil(self.skipWaiting())
})
self.addEventListener('activate', function (event) {
event.waitUntil(self.clients.claim())
})
self.addEventListener('push', function (event) {
if (!event.data) return
let payload
try {
payload = event.data.json()
} catch (e) {
payload = { title: 'Reward App', body: event.data.text() }
}
const title = payload.title || 'Reward App'
// Expiry-warning notifications are informational only — no action buttons
const actions =
payload.type === 'chore_expiring_soon'
? []
: [
{ action: 'approve', title: 'Approve' },
{ action: 'deny', title: 'Deny' },
]
const options = {
body: payload.body || '',
icon: '/icons/icon-192x192.png',
data: payload,
actions,
}
event.waitUntil(self.registration.showNotification(title, options))
})
self.addEventListener('notificationclick', function (event) {
event.notification.close()
const payload = event.notification.data || {}
const approveToken = payload.approve_token
const denyToken = payload.deny_token
const childId = payload.child_id
const entityId = payload.entity_id
const entityType = payload.entity_type
function navigateOrOpen(url) {
return clients
.matchAll({ type: 'window', includeUncontrolled: true })
.then(function (clientList) {
const sameOriginClients = clientList.filter(function (c) {
return new URL(c.url).origin === self.location.origin
})
if (sameOriginClients.length > 0) {
const client = sameOriginClients[0]
return client.focus().then(function () {
return client.navigate(url)
})
}
return clients.openWindow(url)
})
}
function executeDigestAction(token) {
return fetch('/api/digest-action/' + token, {
method: 'POST',
credentials: 'include',
})
.then(function (res) {
if (res.ok) {
// Action executed — navigate to parent view to show the result
var successUrl =
childId && entityId && entityType
? '/parent/' + childId + '?scrollTo=' + entityId + '&entityType=' + entityType
: '/parent'
return navigateOrOpen(successUrl)
}
if (res.status === 401) {
// Not authenticated — navigate with digestToken so the PIN flow executes the action
var authUrl =
childId && entityId && entityType
? '/parent/' +
childId +
'?digestToken=' +
token +
'&scrollTo=' +
entityId +
'&entityType=' +
entityType
: '/parent'
return navigateOrOpen(authUrl)
}
// Token invalid/used/expired — navigate to parent
return navigateOrOpen(childId ? '/parent/' + childId : '/parent')
})
.catch(function () {
return navigateOrOpen('/parent')
})
}
if (event.action === 'approve' && approveToken) {
event.waitUntil(executeDigestAction(approveToken))
return
}
if (event.action === 'deny' && denyToken) {
event.waitUntil(executeDigestAction(denyToken))
return
}
// Body tap — open or focus the app then navigate to the deep link
const deepLinkUrl =
childId && entityId && entityType
? '/parent/' + childId + '?scrollTo=' + entityId + '&entityType=' + entityType
: '/parent'
event.waitUntil(navigateOrOpen(deepLinkUrl))
})