feat(tutorial): update tutorial labels and modal titles to improve clarity
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 3m12s

- Changed "Skip tour" button to "Cancel" in various tutorial overlays.
- Updated modal titles from "Confirm Task" to "Confirm Penalty" where applicable.
- Modified tutorial step call-to-action labels from "Got it" and "Next" to "Continue" for consistency.
- Added tests for new tutorial overlay behavior and button interactions.
- Refactored tutorial controller to allow ignoring tutorial enabled state in step visibility checks.
- Enhanced user profile tutorial restart functionality with appropriate modal messages.
- Updated user profile and task confirmation dialog components to reflect new titles and messages.
- Adjusted configuration files for local development environments.
This commit is contained in:
2026-07-25 12:56:18 -04:00
parent cc1189cd9b
commit 8e4f89f4ec
22 changed files with 347 additions and 118 deletions
+6 -6
View File
@@ -2,20 +2,20 @@
"cookies": [
{
"name": "refresh_token",
"value": "qYJH5LMH5O4UK92tdAp7R49rzGACFvTMVj29S-Pzygc",
"value": "hW7OJbUjHr4XntQRPtefKNhvvctK014R6pzLz_vyJ8g",
"domain": "localhost",
"path": "/api/auth",
"expires": 1792435594.088715,
"expires": 1792774142.289068,
"httpOnly": true,
"secure": true,
"sameSite": "Strict"
},
{
"name": "access_token",
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImUyZS1jY0B0ZXN0LmNvbSIsInVzZXJfaWQiOiI2NmNlMzgzMy0zMGQ3LTRjMTItYjRhMi1iNmIxMjcxYTI1YzEiLCJ0b2tlbl92ZXJzaW9uIjowLCJleHAiOjE3ODQ2NzAzOTR9.jkyiFTxBQ0oatY6jCAWFG88E8e6mCrDDlN_8I56RMBA",
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImUyZS1jY0B0ZXN0LmNvbSIsInVzZXJfaWQiOiI5MjUwNzY1MS00YjlmLTRkMTMtOTgxYS1hMzA2ZThjY2JmNzciLCJ0b2tlbl92ZXJzaW9uIjowLCJleHAiOjE3ODUwMDg5NDJ9.15hDvKf9u95pMzyeSbrHesFBDGgTwnxV1FD175p72-w",
"domain": "localhost",
"path": "/",
"expires": 1784670394.088677,
"expires": 1785008942.288088,
"httpOnly": true,
"secure": true,
"sameSite": "Lax"
@@ -27,11 +27,11 @@
"localStorage": [
{
"name": "authSyncEvent",
"value": "{\"type\":\"logout\",\"at\":1784659593888}"
"value": "{\"type\":\"logout\",\"at\":1784998141942}"
},
{
"name": "parentAuth",
"value": "{\"expiresAt\":1784832394248}"
"value": "{\"expiresAt\":1785170942553}"
}
]
}
+6 -6
View File
@@ -2,20 +2,20 @@
"cookies": [
{
"name": "refresh_token",
"value": "LZA3Bk15HR3io_q8vfyqD3wlRoyV-GJwY-MjWvtUQzg",
"value": "ND-PngBFXIuDrD3eLsaPs1mWqwzusUSI6nPw-M3JjJo",
"domain": "localhost",
"path": "/api/auth",
"expires": 1792435594.060453,
"expires": 1792774029.131567,
"httpOnly": true,
"secure": true,
"sameSite": "Strict"
},
{
"name": "access_token",
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImUyZS10dXRvcmlhbEB0ZXN0LmNvbSIsInVzZXJfaWQiOiJjYjQyMzZkNC1kNDRlLTQ0YjMtOTYzYi0xYTUwMWEzZjM2NTMiLCJ0b2tlbl92ZXJzaW9uIjowLCJleHAiOjE3ODQ2NzAzOTR9.pPd0JYgaAyn4_0YPOlxKoX1B9Ka4Vq2M3CpNcl7EDAU",
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImUyZS10dXRvcmlhbEB0ZXN0LmNvbSIsInVzZXJfaWQiOiJkM2E5OWI5MC1kZDdlLTQ5MjQtYTZkZS1hMWU1OTcxMTE3NDciLCJ0b2tlbl92ZXJzaW9uIjowLCJleHAiOjE3ODUwMDg4Mjl9.ey7BplN-ghoJ8OGMkdOJavVAYVM_bv_xRBrtL02ASjQ",
"domain": "localhost",
"path": "/",
"expires": 1784670394.06041,
"expires": 1785008829.130873,
"httpOnly": true,
"secure": true,
"sameSite": "Lax"
@@ -27,11 +27,11 @@
"localStorage": [
{
"name": "authSyncEvent",
"value": "{\"type\":\"logout\",\"at\":1784659593886}"
"value": "{\"type\":\"logout\",\"at\":1784998028750}"
},
{
"name": "parentAuth",
"value": "{\"expiresAt\":1784832394232}"
"value": "{\"expiresAt\":1785170829369}"
}
]
}
+6 -6
View File
@@ -2,20 +2,20 @@
"cookies": [
{
"name": "refresh_token",
"value": "MYMeAyxeWQy7LVHrJsvF-10FozU5Ko_QoEvmV3bHwPc",
"value": "PbjRbjt9aqRjxoNjBDVJTuDsEEzgUPoplaNgzhOOwdQ",
"domain": "localhost",
"path": "/api/auth",
"expires": 1792435592.056481,
"expires": 1792774174.76082,
"httpOnly": true,
"secure": true,
"sameSite": "Strict"
},
{
"name": "access_token",
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImUyZUB0ZXN0LmNvbSIsInVzZXJfaWQiOiJiODJhZDU2Mi03MjMwLTRkN2EtODU3NS04N2FhNzE1ZWNhMjQiLCJ0b2tlbl92ZXJzaW9uIjowLCJleHAiOjE3ODQ2NzAzOTJ9.iEbCtV3csb9AUWoXL4MJ-GLL1yiJDumvYmKr-vyuwBg",
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImUyZUB0ZXN0LmNvbSIsInVzZXJfaWQiOiI4YzU1MWFiNi1lNmMxLTQ1MzgtOTEzNS0xNDgwN2M2NjM0OTQiLCJ0b2tlbl92ZXJzaW9uIjowLCJleHAiOjE3ODUwMDg5NzR9._hCAKJRJgq4gcDKppcjkcWf9nX94wjBfa4J94Lh2ZlI",
"domain": "localhost",
"path": "/",
"expires": 1784670392.056434,
"expires": 1785008974.760293,
"httpOnly": true,
"secure": true,
"sameSite": "Lax"
@@ -27,11 +27,11 @@
"localStorage": [
{
"name": "authSyncEvent",
"value": "{\"type\":\"logout\",\"at\":1784659591903}"
"value": "{\"type\":\"logout\",\"at\":1784998174529}"
},
{
"name": "parentAuth",
"value": "{\"expiresAt\":1784832392197}"
"value": "{\"expiresAt\":1785170974948}"
}
]
}
@@ -15,7 +15,7 @@ test.describe('Create Child', () => {
// Navigate to parent list and wait for it to fully load before clicking Add Child
await gotoParentList(page)
// Dismiss tutorial overlay if present — it intercepts pointer events
const skip = page.getByRole('button', { name: 'Skip tour' })
const skip = page.getByRole('button', { name: 'Cancel' })
if (await skip.isVisible({ timeout: 1000 }).catch(() => false)) {
await skip.click()
}
@@ -5,7 +5,7 @@ test.describe('Parent profile button temporary parent mode', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/parent')
// Dismiss tutorial overlay if present — it intercepts pointer events
const skip = page.getByRole('button', { name: 'Skip tour' })
const skip = page.getByRole('button', { name: 'Cancel' })
if (await skip.isVisible({ timeout: 1000 }).catch(() => false)) {
await skip.click()
}
@@ -5,7 +5,7 @@ test.describe('Parent profile button permanent parent mode', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/parent')
// Dismiss tutorial overlay if present — it intercepts pointer events
const skip = page.getByRole('button', { name: 'Skip tour' })
const skip = page.getByRole('button', { name: 'Cancel' })
if (await skip.isVisible({ timeout: 1000 }).catch(() => false)) {
await skip.click()
}
@@ -244,7 +244,7 @@ test.describe('Dialog help button and titles', () => {
await card.click()
await expect(modalBackdrop(page)).toBeVisible({ timeout: 3000 })
await expect(page.locator('.modal-title')).toHaveText('Confirm Task')
await expect(page.locator('.modal-title')).toHaveText('Confirm Penalty')
await expect(helpButton(page)).not.toBeVisible()
await page.getByRole('button', { name: 'Cancel' }).click()
@@ -146,7 +146,7 @@ async function expectTutorialCard(page: Page, title: string): Promise<void> {
async function dismissTutorial(page: Page): Promise<void> {
const card = getTutorialCard(page)
if (await card.isVisible({ timeout: 1000 }).catch(() => false)) {
// Use "Skip tour" to clear the active step and drain the queue in one
// Use "Cancel" to clear the active step and drain the queue in one
// action, avoiding chained steps that would keep the card visible.
await page.locator('.tutorial-root .btn-skip').click()
await expect(card).not.toBeVisible({ timeout: 5000 })