Files
encoach_backend_v4/custom_addons/encoach_portal/views/templates.xml
Yamen Ahmad 907a5c0e92 feat(v3): restructure project + add complete frontend
- Restructure: move backend from new_project/ to backend/
- Add full React/TypeScript frontend (37 pages, 17 services, 16 type defs, 11 query hooks)
- Add docs/ with SRS specs, user stories, and workflow documentation
- Update .gitignore for new directory layout

Workflows implemented:
  WF1 User Signup, WF2 Placement Test, WF3 Exam Configuration,
  WF4 General English Exam, WF5 Course Generation,
  WF6 Entity Student Onboarding, AI Course Generation,
  Adaptive Learning Engine UI, White-Label Branding, Score Release

Made-with: Cursor
2026-04-10 17:26:42 +04:00

859 lines
57 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<!-- ===================================================================
REGISTER PAGE
=================================================================== -->
<template id="register" name="EnCoach Register">
<t t-call="website.layout">
<div id="wrap" class="oe_structure">
<section class="ec-register-section py-5">
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-5 col-md-7">
<div class="card shadow-sm border-0 rounded-4">
<div class="card-body p-4 p-md-5">
<div class="text-center mb-4">
<h2 class="fw-bold text-primary mb-1">Create Account</h2>
<p class="text-muted">Start your learning journey with EnCoach</p>
</div>
<form action="/register" method="post" class="ec-register-form">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<div class="mb-3">
<label for="reg_name" class="form-label fw-semibold">Full Name</label>
<div class="input-group">
<span class="input-group-text bg-light border-end-0"><i class="fa fa-user text-muted"/></span>
<input type="text" id="reg_name" name="name" class="form-control border-start-0" placeholder="Enter your full name" required="required"/>
</div>
</div>
<div class="mb-3">
<label for="reg_email" class="form-label fw-semibold">Email Address</label>
<div class="input-group">
<span class="input-group-text bg-light border-end-0"><i class="fa fa-envelope text-muted"/></span>
<input type="email" id="reg_email" name="email" class="form-control border-start-0" placeholder="you@example.com" required="required"/>
</div>
</div>
<div class="mb-3">
<label for="reg_password" class="form-label fw-semibold">Password</label>
<div class="input-group">
<span class="input-group-text bg-light border-end-0"><i class="fa fa-lock text-muted"/></span>
<input type="password" id="reg_password" name="password" class="form-control border-start-0" placeholder="Min. 8 characters" required="required" minlength="8"/>
</div>
<div class="ec-password-strength mt-2">
<div class="progress" style="height: 4px;">
<div id="password_strength_bar" class="progress-bar" role="progressbar" style="width: 0%;"/>
</div>
<small id="password_strength_text" class="text-muted"/>
</div>
</div>
<div class="mb-4">
<label for="reg_confirm" class="form-label fw-semibold">Confirm Password</label>
<div class="input-group">
<span class="input-group-text bg-light border-end-0"><i class="fa fa-lock text-muted"/></span>
<input type="password" id="reg_confirm" name="confirm_password" class="form-control border-start-0" placeholder="Re-enter password" required="required"/>
</div>
</div>
<t t-if="captcha_site_key">
<div class="mb-4 d-flex justify-content-center">
<div class="ec-captcha-placeholder border rounded-3 p-3 text-center bg-light w-100">
<small class="text-muted"><i class="fa fa-shield me-1"/>CAPTCHA verification</small>
<div t-att-data-sitekey="captcha_site_key" class="g-recaptcha mt-2" data-callback="onCaptchaSuccess"/>
</div>
</div>
</t>
<button type="submit" class="btn btn-primary w-100 py-2 fw-semibold rounded-3">
<i class="fa fa-user-plus me-2"/>Create Account
</button>
</form>
<div class="text-center mt-4">
<span class="text-muted">Already have an account?</span>
<a href="/web/login" class="fw-semibold text-decoration-none ms-1">Sign In</a>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
</t>
</template>
<!-- ===================================================================
VERIFY EMAIL PAGE
=================================================================== -->
<template id="verify_email" name="EnCoach Verify Email">
<t t-call="website.layout">
<div id="wrap" class="oe_structure">
<section class="ec-verify-section py-5">
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-5 col-md-7">
<div class="card shadow-sm border-0 rounded-4">
<div class="card-body p-4 p-md-5 text-center">
<div class="ec-verify-icon mb-4">
<span class="d-inline-flex align-items-center justify-content-center rounded-circle bg-primary bg-opacity-10" style="width:72px;height:72px;">
<i class="fa fa-envelope-open fa-2x text-primary"/>
</span>
</div>
<h2 class="fw-bold mb-2">Check Your Email</h2>
<p class="text-muted mb-1">We sent a verification code to</p>
<p class="fw-semibold mb-4" t-esc="email"/>
<form action="/verify-email" method="post">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<input type="hidden" name="email" t-att-value="email"/>
<div class="ec-otp-inputs d-flex justify-content-center gap-2 mb-4">
<input type="text" name="otp_1" maxlength="1" class="form-control text-center fw-bold fs-4 rounded-3 ec-otp-box" required="required"/>
<input type="text" name="otp_2" maxlength="1" class="form-control text-center fw-bold fs-4 rounded-3 ec-otp-box" required="required"/>
<input type="text" name="otp_3" maxlength="1" class="form-control text-center fw-bold fs-4 rounded-3 ec-otp-box" required="required"/>
<input type="text" name="otp_4" maxlength="1" class="form-control text-center fw-bold fs-4 rounded-3 ec-otp-box" required="required"/>
<input type="text" name="otp_5" maxlength="1" class="form-control text-center fw-bold fs-4 rounded-3 ec-otp-box" required="required"/>
<input type="text" name="otp_6" maxlength="1" class="form-control text-center fw-bold fs-4 rounded-3 ec-otp-box" required="required"/>
</div>
<button type="submit" class="btn btn-primary w-100 py-2 fw-semibold rounded-3 mb-3">
Verify Email
</button>
</form>
<p class="text-muted mb-0">
Didn't receive the code?
<a href="#" class="fw-semibold text-decoration-none ec-resend-btn">Resend</a>
</p>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
</t>
</template>
<!-- ===================================================================
ONBOARDING PAGE (OWL Wizard mount point)
=================================================================== -->
<template id="onboarding" name="EnCoach Onboarding">
<t t-call="website.layout">
<div id="wrap" class="oe_structure">
<section class="ec-onboarding-section py-5">
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-8 col-md-10">
<div class="text-center mb-4">
<h2 class="fw-bold">Welcome, <t t-esc="user.name"/>!</h2>
<p class="text-muted">Let's personalise your learning experience</p>
</div>
<!-- OWL wizard mounts here -->
<div id="ec_onboarding_wizard"
t-att-data-user-id="user.id"
t-att-data-profile-id="profile.id if profile else ''"/>
</div>
</div>
</div>
</section>
</div>
</t>
</template>
<!-- ===================================================================
STUDENT DASHBOARD
=================================================================== -->
<template id="student_dashboard" name="EnCoach Student Dashboard">
<t t-call="website.layout">
<div id="wrap" class="oe_structure">
<section class="ec-dashboard-section py-5">
<div class="container">
<!-- Welcome Header -->
<div class="row align-items-center mb-5">
<div class="col">
<h2 class="fw-bold mb-1">Welcome back, <t t-esc="user.name"/>!</h2>
<p class="text-muted mb-0">
<t t-if="profile and profile.cefr_level">
Your current level:
<span class="badge rounded-pill bg-primary fs-6 ms-1" t-esc="profile.cefr_level"/>
</t>
<t t-else="">
<span class="text-warning"><i class="fa fa-exclamation-circle me-1"/>Take a placement test to find your level</span>
</t>
</p>
</div>
<div class="col-auto">
<a href="/my/placement" class="btn btn-outline-primary rounded-3">
<i class="fa fa-compass me-1"/>Placement Test
</a>
</div>
</div>
<!-- Quick Actions -->
<div class="row g-3 mb-5">
<div class="col-md-4">
<a href="/my/placement" class="card border-0 shadow-sm rounded-4 h-100 text-decoration-none ec-action-card">
<div class="card-body d-flex align-items-center p-4">
<span class="d-inline-flex align-items-center justify-content-center rounded-3 bg-primary bg-opacity-10 me-3" style="width:48px;height:48px;">
<i class="fa fa-play text-primary"/>
</span>
<div>
<h6 class="fw-bold mb-0">Start Placement</h6>
<small class="text-muted">Find your level</small>
</div>
</div>
</a>
</div>
<div class="col-md-4">
<a href="#courses_section" class="card border-0 shadow-sm rounded-4 h-100 text-decoration-none ec-action-card">
<div class="card-body d-flex align-items-center p-4">
<span class="d-inline-flex align-items-center justify-content-center rounded-3 bg-success bg-opacity-10 me-3" style="width:48px;height:48px;">
<i class="fa fa-book text-success"/>
</span>
<div>
<h6 class="fw-bold mb-0">Resume Course</h6>
<small class="text-muted">Continue learning</small>
</div>
</div>
</a>
</div>
<div class="col-md-4">
<a href="#results_section" class="card border-0 shadow-sm rounded-4 h-100 text-decoration-none ec-action-card">
<div class="card-body d-flex align-items-center p-4">
<span class="d-inline-flex align-items-center justify-content-center rounded-3 bg-info bg-opacity-10 me-3" style="width:48px;height:48px;">
<i class="fa fa-bar-chart text-info"/>
</span>
<div>
<h6 class="fw-bold mb-0">View Results</h6>
<small class="text-muted">Track progress</small>
</div>
</div>
</a>
</div>
</div>
<!-- Courses Grid -->
<div id="courses_section" class="mb-5">
<h4 class="fw-bold mb-3"><i class="fa fa-graduation-cap me-2 text-primary"/>My Courses</h4>
<t t-if="courses">
<div class="row g-4">
<t t-foreach="courses" t-as="course">
<div class="col-md-6 col-lg-4">
<div class="card border-0 shadow-sm rounded-4 h-100 ec-course-card">
<div class="card-body p-4">
<h5 class="fw-bold mb-2" t-esc="course.name"/>
<p class="text-muted small mb-3" t-esc="course.code or 'No description'"/>
<div class="progress rounded-pill mb-2" style="height: 8px;">
<div class="progress-bar bg-primary rounded-pill" role="progressbar" style="width: 0%;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"/>
</div>
<div class="d-flex justify-content-between align-items-center mt-3">
<small class="text-muted">0% complete</small>
<a t-attf-href="/my/course/#{course.id}" class="btn btn-sm btn-outline-primary rounded-3">Continue</a>
</div>
</div>
</div>
</div>
</t>
</div>
</t>
<t t-else="">
<div class="card border-0 bg-light rounded-4 p-4 text-center">
<p class="text-muted mb-0"><i class="fa fa-info-circle me-1"/>No courses enrolled yet. Complete your placement test to get started.</p>
</div>
</t>
</div>
<!-- Recent Results -->
<div id="results_section">
<h4 class="fw-bold mb-3"><i class="fa fa-trophy me-2 text-warning"/>Recent Exam Results</h4>
<t t-if="attempts">
<div class="table-responsive">
<table class="table table-hover align-middle bg-white rounded-4 overflow-hidden shadow-sm">
<thead class="table-light">
<tr>
<th>Exam</th>
<th>Date</th>
<th>Status</th>
<th class="text-end">Action</th>
</tr>
</thead>
<tbody>
<t t-foreach="attempts" t-as="a">
<tr>
<td class="fw-semibold" t-esc="a.display_name"/>
<td class="text-muted" t-esc="a.started_at" t-options='{"widget": "date"}'/>
<td>
<span t-attf-class="badge rounded-pill #{('bg-success' if a.status in ('released','scored') else 'bg-secondary')}" t-esc="a.status"/>
</td>
<td class="text-end">
<a t-attf-href="/my/exam/#{a.id}/results" class="btn btn-sm btn-outline-primary rounded-3">View</a>
</td>
</tr>
</t>
</tbody>
</table>
</div>
</t>
<t t-else="">
<div class="card border-0 bg-light rounded-4 p-4 text-center">
<p class="text-muted mb-0"><i class="fa fa-info-circle me-1"/>No exam results yet.</p>
</div>
</t>
</div>
</div>
</section>
</div>
</t>
</template>
<!-- ===================================================================
PLACEMENT BRIEFING
=================================================================== -->
<template id="placement_briefing" name="EnCoach Placement Briefing">
<t t-call="website.layout">
<div id="wrap" class="oe_structure">
<section class="ec-placement-section py-5">
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-7 col-md-9">
<div class="card border-0 shadow-sm rounded-4">
<div class="card-body p-4 p-md-5">
<div class="text-center mb-4">
<span class="d-inline-flex align-items-center justify-content-center rounded-circle bg-primary bg-opacity-10 mb-3" style="width:80px;height:80px;">
<i class="fa fa-flask fa-2x text-primary"/>
</span>
<h2 class="fw-bold">Placement Test</h2>
<p class="text-muted">Discover your current proficiency level</p>
</div>
<div class="ec-test-overview mb-4">
<h5 class="fw-bold mb-3">What this test covers</h5>
<div class="row g-3">
<div class="col-6">
<div class="d-flex align-items-start">
<i class="fa fa-check-circle text-success mt-1 me-2"/>
<span>Reading Comprehension</span>
</div>
</div>
<div class="col-6">
<div class="d-flex align-items-start">
<i class="fa fa-check-circle text-success mt-1 me-2"/>
<span>Listening Skills</span>
</div>
</div>
<div class="col-6">
<div class="d-flex align-items-start">
<i class="fa fa-check-circle text-success mt-1 me-2"/>
<span>Grammar &amp; Vocabulary</span>
</div>
</div>
<div class="col-6">
<div class="d-flex align-items-start">
<i class="fa fa-check-circle text-success mt-1 me-2"/>
<span>Problem Solving</span>
</div>
</div>
</div>
</div>
<div class="ec-test-info bg-light rounded-3 p-3 mb-4">
<div class="row text-center">
<div class="col-4">
<div class="fw-bold text-primary fs-5">~25</div>
<small class="text-muted">Minutes</small>
</div>
<div class="col-4">
<div class="fw-bold text-primary fs-5">Adaptive</div>
<small class="text-muted">Difficulty</small>
</div>
<div class="col-4">
<div class="fw-bold text-primary fs-5">CEFR</div>
<small class="text-muted">A1 C2</small>
</div>
</div>
</div>
<h5 class="fw-bold mb-3">Before you begin</h5>
<ul class="list-unstyled mb-4">
<li class="d-flex align-items-start mb-2">
<span class="badge bg-primary bg-opacity-10 text-primary rounded-circle me-2 mt-1" style="width:24px;height:24px;line-height:24px;font-size:.75rem;">1</span>
<span>Find a quiet place with a stable internet connection</span>
</li>
<li class="d-flex align-items-start mb-2">
<span class="badge bg-primary bg-opacity-10 text-primary rounded-circle me-2 mt-1" style="width:24px;height:24px;line-height:24px;font-size:.75rem;">2</span>
<span>The test adapts to your answers — do your best on every question</span>
</li>
<li class="d-flex align-items-start mb-2">
<span class="badge bg-primary bg-opacity-10 text-primary rounded-circle me-2 mt-1" style="width:24px;height:24px;line-height:24px;font-size:.75rem;">3</span>
<span>You cannot pause or restart once you begin</span>
</li>
<li class="d-flex align-items-start">
<span class="badge bg-primary bg-opacity-10 text-primary rounded-circle me-2 mt-1" style="width:24px;height:24px;line-height:24px;font-size:.75rem;">4</span>
<span>Results are available immediately upon completion</span>
</li>
</ul>
<div class="text-center">
<a href="/my/placement/start" class="btn btn-primary btn-lg px-5 py-2 rounded-3 fw-semibold">
<i class="fa fa-play me-2"/>Begin Test
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
</t>
</template>
<!-- ===================================================================
PLACEMENT RESULTS
=================================================================== -->
<template id="placement_results" name="EnCoach Placement Results">
<t t-call="website.layout">
<div id="wrap" class="oe_structure">
<section class="ec-results-section py-5">
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-8 col-md-10">
<!-- CEFR Level Badge -->
<div class="text-center mb-5">
<h2 class="fw-bold mb-3">Your Placement Results</h2>
<t t-if="session">
<div class="ec-cefr-badge d-inline-flex align-items-center justify-content-center rounded-circle bg-primary text-white shadow" style="width:120px;height:120px;">
<span class="fs-1 fw-bold" t-esc="session.final_cefr or '—'"/>
</div>
<p class="mt-3 text-muted">CEFR Level</p>
</t>
<t t-else="">
<div class="alert alert-warning rounded-3">No completed placement session found.</div>
</t>
</div>
<!-- Skill Radar Chart (OWL mount point) -->
<t t-if="abilities">
<div class="card border-0 shadow-sm rounded-4 mb-4">
<div class="card-body p-4">
<h5 class="fw-bold mb-3">Skill Overview</h5>
<div id="ec_skill_radar_chart" class="ec-chart-container" style="height:300px;"
t-att-data-abilities="json.dumps([{'skill': a.skill_id.name, 'theta': a.theta} for a in abilities])"/>
</div>
</div>
<!-- Per-Skill Breakdown -->
<div class="card border-0 shadow-sm rounded-4 mb-4">
<div class="card-body p-4">
<h5 class="fw-bold mb-3">Skill Breakdown</h5>
<t t-foreach="abilities" t-as="ability">
<div class="d-flex align-items-center mb-3">
<div class="me-3" style="min-width:120px;">
<span class="fw-semibold" t-esc="ability.skill_id.name or 'Skill'"/>
</div>
<div class="flex-grow-1">
<div class="progress rounded-pill" style="height:10px;">
<div class="progress-bar bg-primary rounded-pill" role="progressbar"
t-attf-style="width: #{min(max(int((ability.theta + 3) / 6 * 100), 0), 100)}%;"
t-att-aria-valuenow="ability.theta"/>
</div>
</div>
<div class="ms-3 text-end" style="min-width:60px;">
<span class="fw-semibold" t-esc="'%.2f' % ability.theta"/>
</div>
</div>
</t>
</div>
</div>
</t>
<!-- Recommended Path -->
<div class="card border-0 shadow-sm rounded-4">
<div class="card-body p-4 text-center">
<h5 class="fw-bold mb-2">Recommended Learning Path</h5>
<p class="text-muted mb-3">Based on your results, we've tailored a course path for you.</p>
<a href="/my/dashboard" class="btn btn-primary rounded-3 px-4">
<i class="fa fa-arrow-right me-2"/>Go to Dashboard
</a>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
</t>
</template>
<!-- ===================================================================
COURSE DETAIL
=================================================================== -->
<template id="course_detail" name="EnCoach Course Detail">
<t t-call="website.layout">
<div id="wrap" class="oe_structure">
<section class="ec-course-section py-5">
<div class="container">
<!-- Course Header -->
<div class="card border-0 shadow-sm rounded-4 mb-4">
<div class="card-body p-4 p-md-5">
<div class="row align-items-center">
<div class="col-md-8">
<h2 class="fw-bold mb-2" t-esc="course.name"/>
<p class="text-muted mb-3" t-esc="course.code or 'No description available.'"/>
</div>
<div class="col-md-4 text-md-end">
<div class="ec-progress-ring text-center">
<div class="fs-2 fw-bold text-primary">0%</div>
<small class="text-muted">Complete</small>
</div>
</div>
</div>
<div class="progress rounded-pill mt-3" style="height:10px;">
<div class="progress-bar bg-primary rounded-pill" role="progressbar" style="width:0%;"/>
</div>
</div>
</div>
<!-- Module List -->
<h4 class="fw-bold mb-3"><i class="fa fa-list-ul me-2 text-primary"/>Modules</h4>
<t t-if="modules">
<div class="ec-module-list">
<t t-foreach="modules" t-as="mod">
<div t-attf-class="card border-0 shadow-sm rounded-4 mb-3 #{('ec-module-locked' if mod.status == 'locked' else '')}">
<div class="card-body p-4">
<div class="d-flex align-items-center">
<div class="me-3">
<t t-if="mod.status == 'completed'">
<span class="d-inline-flex align-items-center justify-content-center rounded-circle bg-success text-white" style="width:40px;height:40px;">
<i class="fa fa-check"/>
</span>
</t>
<t t-elif="mod.status == 'locked'">
<span class="d-inline-flex align-items-center justify-content-center rounded-circle bg-secondary bg-opacity-25 text-secondary" style="width:40px;height:40px;">
<i class="fa fa-lock"/>
</span>
</t>
<t t-else="">
<span class="d-inline-flex align-items-center justify-content-center rounded-circle bg-primary bg-opacity-10 text-primary" style="width:40px;height:40px;">
<i class="fa fa-play"/>
</span>
</t>
</div>
<div class="flex-grow-1">
<h6 class="fw-bold mb-1" t-esc="mod.name"/>
<small class="text-muted" t-esc="mod.cefr_target or ''"/>
</div>
<div class="ms-3">
<t t-if="mod.status != 'locked'">
<span class="badge rounded-pill bg-primary bg-opacity-10 text-primary" t-esc="mod.status or 'available'"/>
</t>
</div>
</div>
</div>
</div>
</t>
</div>
</t>
<t t-else="">
<div class="card border-0 bg-light rounded-4 p-4 text-center">
<p class="text-muted mb-0">No modules available yet for this course.</p>
</div>
</t>
</div>
</section>
</div>
</t>
</template>
<!-- ===================================================================
EXAM RESULTS
=================================================================== -->
<template id="exam_results" name="EnCoach Exam Results">
<t t-call="website.layout">
<div id="wrap" class="oe_structure">
<section class="ec-exam-results-section py-5">
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-8 col-md-10">
<!-- Score Summary Card -->
<div class="card border-0 shadow-sm rounded-4 mb-4">
<div class="card-body p-4 p-md-5 text-center">
<h2 class="fw-bold mb-3">Exam Results</h2>
<div class="row g-4 mb-4">
<div class="col-sm-4">
<div class="ec-score-highlight bg-primary bg-opacity-10 rounded-4 p-3">
<div class="fs-2 fw-bold text-primary" t-esc="'%.1f' % attempt.overall_band if attempt.overall_band else '—'"/>
<small class="text-muted d-block">Overall Band</small>
</div>
</div>
<div class="col-sm-4">
<div class="ec-score-highlight bg-success bg-opacity-10 rounded-4 p-3">
<div class="fs-2 fw-bold text-success" t-esc="attempt.cefr_level or '—'"/>
<small class="text-muted d-block">CEFR Level</small>
</div>
</div>
<div class="col-sm-4">
<div class="ec-score-highlight bg-info bg-opacity-10 rounded-4 p-3">
<div class="fs-2 fw-bold text-info" t-esc="attempt.status or '—'"/>
<small class="text-muted d-block">Status</small>
</div>
</div>
</div>
</div>
</div>
<!-- Skill Scores -->
<t t-if="scores">
<div class="card border-0 shadow-sm rounded-4 mb-4">
<div class="card-body p-4">
<h5 class="fw-bold mb-3">Skill Scores</h5>
<t t-foreach="scores" t-as="score">
<div class="mb-3">
<div class="d-flex justify-content-between mb-1">
<span class="fw-semibold" t-esc="score.skill_name or score.display_name"/>
<span class="fw-bold text-primary" t-esc="'%.1f' % score.value if score.value else '—'"/>
</div>
<div class="progress rounded-pill" style="height:10px;">
<div class="progress-bar bg-primary rounded-pill" role="progressbar"
t-attf-style="width: #{min(int(score.value / 9.0 * 100), 100) if score.value else 0}%;"/>
</div>
</div>
</t>
</div>
</div>
</t>
<!-- Feedback -->
<t t-if="feedback">
<div class="card border-0 shadow-sm rounded-4 mb-4">
<div class="card-body p-4">
<h5 class="fw-bold mb-3"><i class="fa fa-comments me-2 text-warning"/>Feedback</h5>
<t t-foreach="feedback" t-as="fb">
<div class="ec-feedback-item bg-light rounded-3 p-3 mb-2">
<strong t-esc="fb.skill_name or 'General'"/>
<p class="mb-0 mt-1 text-muted" t-esc="fb.text or fb.comment or ''"/>
</div>
</t>
</div>
</div>
</t>
<!-- Actions -->
<div class="d-flex flex-wrap gap-3 justify-content-center">
<a t-attf-href="/my/exam/#{attempt.id}/pdf" class="btn btn-outline-primary rounded-3 px-4">
<i class="fa fa-download me-2"/>Download PDF
</a>
<t t-if="attempt.verification_hash">
<a t-attf-href="/verify/#{attempt.verification_hash}" class="btn btn-outline-secondary rounded-3 px-4" target="_blank">
<i class="fa fa-qrcode me-2"/>Verify Score
</a>
</t>
<a href="/my/dashboard" class="btn btn-primary rounded-3 px-4">
<i class="fa fa-arrow-left me-2"/>Back to Dashboard
</a>
</div>
</div>
</div>
</div>
</section>
</div>
</t>
</template>
<!-- ===================================================================
RESULTS PENDING
=================================================================== -->
<template id="results_pending" name="EnCoach Results Pending">
<t t-call="website.layout">
<div id="wrap" class="oe_structure">
<section class="ec-pending-section py-5">
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-6 col-md-8 text-center">
<div class="card border-0 shadow-sm rounded-4">
<div class="card-body p-5">
<span class="d-inline-flex align-items-center justify-content-center rounded-circle bg-warning bg-opacity-10 mb-4" style="width:80px;height:80px;">
<i class="fa fa-clock-o fa-2x text-warning"/>
</span>
<h3 class="fw-bold mb-2">Results Not Yet Released</h3>
<p class="text-muted mb-4">
Your exam (<strong t-esc="attempt.display_name"/>) is still being processed.
Please check back later.
</p>
<div class="d-flex gap-3 justify-content-center">
<a href="/my/dashboard" class="btn btn-primary rounded-3 px-4">
<i class="fa fa-arrow-left me-2"/>Dashboard
</a>
<button class="btn btn-outline-secondary rounded-3 px-4" onclick="location.reload();">
<i class="fa fa-refresh me-2"/>Refresh
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
</t>
</template>
<!-- ===================================================================
PROFILE PAGE
=================================================================== -->
<template id="profile" name="EnCoach Profile">
<t t-call="website.layout">
<div id="wrap" class="oe_structure">
<section class="ec-profile-section py-5">
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-7 col-md-9">
<h2 class="fw-bold mb-4">My Profile</h2>
<!-- Profile Form -->
<div class="card border-0 shadow-sm rounded-4 mb-4">
<div class="card-body p-4">
<h5 class="fw-bold mb-3">Personal Information</h5>
<form action="/my/profile" method="post">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<div class="row g-3">
<div class="col-md-6">
<label for="prof_name" class="form-label fw-semibold">Full Name</label>
<input type="text" id="prof_name" name="name" class="form-control rounded-3" t-att-value="user.name" required="required"/>
</div>
<div class="col-md-6">
<label for="prof_email" class="form-label fw-semibold">Email</label>
<input type="email" id="prof_email" class="form-control rounded-3 bg-light" t-att-value="user.email" readonly="readonly"/>
</div>
<div class="col-md-6">
<label for="prof_phone" class="form-label fw-semibold">Phone</label>
<input type="tel" id="prof_phone" name="phone" class="form-control rounded-3" t-att-value="user.phone or ''"/>
</div>
<div class="col-md-6">
<label for="prof_prefs" class="form-label fw-semibold">Study Preferences</label>
<select id="prof_prefs" name="study_preference" class="form-select rounded-3">
<option value="self_paced" t-att-selected="profile and profile.study_mode == 'self_paced'">Self-paced</option>
<option value="structured" t-att-selected="profile and profile.study_mode == 'structured'">Structured</option>
<option value="intensive" t-att-selected="profile and profile.study_mode == 'intensive'">Intensive</option>
</select>
</div>
</div>
<button type="submit" class="btn btn-primary rounded-3 mt-4 px-4">
<i class="fa fa-save me-2"/>Save Changes
</button>
</form>
</div>
</div>
<!-- Change Password -->
<div class="card border-0 shadow-sm rounded-4 mb-4">
<div class="card-body p-4">
<h5 class="fw-bold mb-3">Change Password</h5>
<form action="/my/profile/password" method="post">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<div class="mb-3">
<label for="current_pw" class="form-label fw-semibold">Current Password</label>
<input type="password" id="current_pw" name="current_password" class="form-control rounded-3" required="required"/>
</div>
<div class="mb-3">
<label for="new_pw" class="form-label fw-semibold">New Password</label>
<input type="password" id="new_pw" name="new_password" class="form-control rounded-3" required="required" minlength="8"/>
</div>
<div class="mb-3">
<label for="confirm_pw" class="form-label fw-semibold">Confirm New Password</label>
<input type="password" id="confirm_pw" name="confirm_new_password" class="form-control rounded-3" required="required"/>
</div>
<button type="submit" class="btn btn-outline-primary rounded-3 px-4">
<i class="fa fa-key me-2"/>Update Password
</button>
</form>
</div>
</div>
<!-- Entity Info -->
<t t-if="profile and profile.entity_id">
<div class="card border-0 shadow-sm rounded-4">
<div class="card-body p-4">
<h5 class="fw-bold mb-3">Organisation</h5>
<div class="d-flex align-items-center">
<span class="d-inline-flex align-items-center justify-content-center rounded-3 bg-primary bg-opacity-10 me-3" style="width:48px;height:48px;">
<i class="fa fa-building text-primary"/>
</span>
<div>
<h6 class="fw-bold mb-0" t-esc="profile.entity_id.name"/>
<small class="text-muted" t-esc="profile.entity_id.name or ''"/>
</div>
</div>
</div>
</div>
</t>
</div>
</div>
</div>
</section>
</div>
</t>
</template>
<!-- ===================================================================
SCORE VERIFICATION (PUBLIC)
=================================================================== -->
<template id="score_verification" name="EnCoach Score Verification">
<t t-call="website.layout">
<div id="wrap" class="oe_structure">
<section class="ec-verification-section py-5">
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-6 col-md-8">
<div class="card border-0 shadow-sm rounded-4">
<div class="card-body p-4 p-md-5 text-center">
<span class="d-inline-flex align-items-center justify-content-center rounded-circle bg-success bg-opacity-10 mb-4" style="width:80px;height:80px;">
<i class="fa fa-shield fa-2x text-success"/>
</span>
<h2 class="fw-bold mb-2">Score Verification</h2>
<p class="text-muted mb-4">Verify the authenticity of an EnCoach score report</p>
<div class="bg-light rounded-3 p-3 mb-4">
<small class="text-muted d-block mb-1">Verification Code</small>
<code class="fs-5" t-esc="hash_code"/>
</div>
<!-- Verification result loaded dynamically via JS/RPC -->
<div id="ec_verification_result">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Verifying…</span>
</div>
<p class="text-muted mt-2">Looking up results…</p>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
</t>
</template>
</odoo>