feat(tutorial): implement comprehensive tutorial system with step guidance
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 3m9s
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 3m9s
- Added tutorial controller to manage tutorial state and progress. - Introduced HelpButton component for contextual help throughout the application. - Created various tutorial steps for onboarding and feature guidance. - Integrated tutorial prompts in multiple components (ChildrenListView, LoginButton, ScheduleModal, etc.) to enhance user experience. - Implemented logic to show tutorials based on user actions and state. - Added functionality to dismiss and skip tutorial sessions. - Established a mechanism to hydrate tutorial state from user profile.
This commit is contained in:
@@ -95,6 +95,54 @@
|
||||
<button class="btn btn-primary" @click="closeDeleteError">Close</button>
|
||||
</div>
|
||||
</ModalDialog>
|
||||
|
||||
<!-- Help / Tutorial section -->
|
||||
<section class="help-section" aria-labelledby="help-heading">
|
||||
<h3 id="help-heading" class="help-heading">Help</h3>
|
||||
<label class="help-row">
|
||||
<span class="help-row-text">
|
||||
<span class="help-row-label">Show tutorial tips</span>
|
||||
<span class="help-row-desc">Show helpful tips as I use the app.</span>
|
||||
</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
class="help-toggle"
|
||||
:checked="tutorialEnabled"
|
||||
@change="onToggleTutorial"
|
||||
aria-label="Show tutorial tips"
|
||||
/>
|
||||
</label>
|
||||
<button type="button" class="btn-link btn-link-space" @click="openRestartConfirm">
|
||||
Restart tutorial
|
||||
</button>
|
||||
</section>
|
||||
|
||||
<!-- Restart confirmation -->
|
||||
<ModalDialog
|
||||
v-if="showRestartConfirm"
|
||||
title="Restart tutorial?"
|
||||
@close="showRestartConfirm = false"
|
||||
>
|
||||
<div class="modal-message">
|
||||
Start the tour again from the beginning? You'll see the tips again as you use the app.
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button class="btn btn-secondary" @click="showRestartConfirm = false">Cancel</button>
|
||||
<button class="btn btn-primary" @click="confirmRestartTutorial">Restart</button>
|
||||
</div>
|
||||
</ModalDialog>
|
||||
|
||||
<!-- Restart success -->
|
||||
<ModalDialog
|
||||
v-if="showRestartSuccess"
|
||||
title="Tour reset"
|
||||
@close="showRestartSuccess = false"
|
||||
>
|
||||
<div class="modal-message">Tour reset — here we go!</div>
|
||||
<div class="modal-actions">
|
||||
<button class="btn btn-primary" @click="showRestartSuccess = false">OK</button>
|
||||
</div>
|
||||
</ModalDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -113,6 +161,11 @@ import {
|
||||
import { parseErrorResponse, isEmailValid } from '@/common/api'
|
||||
import { ALREADY_MARKED } from '@/common/errorCodes'
|
||||
import { logoutUser, suppressForceLogout } from '@/stores/auth'
|
||||
import {
|
||||
tutorialEnabled,
|
||||
setTutorialEnabled,
|
||||
resetAllProgress,
|
||||
} from '@/tutorial/controller'
|
||||
import '@/assets/styles.css'
|
||||
|
||||
const router = useRouter()
|
||||
@@ -136,6 +189,25 @@ const deleteErrorMessage = ref('')
|
||||
const pushError = ref('')
|
||||
const pushPermissionDenied = ref(false)
|
||||
|
||||
// Tutorial controls
|
||||
const showRestartConfirm = ref(false)
|
||||
const showRestartSuccess = ref(false)
|
||||
|
||||
async function onToggleTutorial(e: Event) {
|
||||
const target = e.target as HTMLInputElement
|
||||
await setTutorialEnabled(target.checked)
|
||||
}
|
||||
|
||||
function openRestartConfirm() {
|
||||
showRestartConfirm.value = true
|
||||
}
|
||||
|
||||
async function confirmRestartTutorial() {
|
||||
showRestartConfirm.value = false
|
||||
await resetAllProgress()
|
||||
showRestartSuccess.value = true
|
||||
}
|
||||
|
||||
const initialData = ref<{
|
||||
image_id: string | null
|
||||
first_name: string
|
||||
@@ -500,4 +572,45 @@ function closeDeleteError() {
|
||||
outline: none;
|
||||
border-color: var(--btn-primary, #4a90e2);
|
||||
}
|
||||
|
||||
.help-section {
|
||||
margin-top: 1.4rem;
|
||||
padding-top: 1.2rem;
|
||||
border-top: 1px solid var(--form-input-border, #cbd5e1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.6rem;
|
||||
}
|
||||
.help-heading {
|
||||
margin: 0 0 0.2rem;
|
||||
font-size: 1rem;
|
||||
color: var(--form-heading, #667eea);
|
||||
}
|
||||
.help-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
.help-row-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.15rem;
|
||||
}
|
||||
.help-row-label {
|
||||
font-weight: 600;
|
||||
color: var(--text-primary, #222);
|
||||
}
|
||||
.help-row-desc {
|
||||
font-size: 0.88rem;
|
||||
color: var(--text-secondary, #888);
|
||||
}
|
||||
.help-toggle {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
margin-top: 2px;
|
||||
accent-color: var(--btn-primary, #667eea);
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user