Loading...

V

🔐 Admin Login

VYROX Kids AI Workshop

{{ loginError }}

{{ toast.type==='success' ? '✅' : '⚠️' }} {{ toast.msg }}
V

Admin Dashboard

{{ adminEmail }}

{{ adminStats.total||0 }}

Total

{{ adminStats.pending||0 }}

Pending

{{ adminStats.approved||0 }}

Approved

{{ adminStats.totalKids||0 }}

Total Kids

RM {{ adminStats.revenue||0 }}

Revenue

#DateGuardianMobileEmailKidsFeeAI AmtStatusActions
{{ app.id }} {{ dayOfWeek(app.workshop_date) }} {{ app.workshop_date }} N/A {{ app.guardian_name }} {{ app.guardian_mobile }} {{ app.guardian_email }}
{{ p.name }} ({{ p.age }}, {{ p.gender }})
RM {{ parseFloat(app.total_fee) }} {{ app.extracted_amount||'-' }}
No registrations found

Registration #{{ viewingApp.id }}

Workshop Date & Time

{{ dayOfWeek(viewingApp.workshop_date) }}, {{ viewingApp.workshop_date || 'N/A' }} · {{ viewingApp.workshop_time || '' }}

Status

{{ viewingApp.status }}

Parent / Guardian Information

Name

{{ viewingApp.guardian_name }}

Mobile

{{ viewingApp.guardian_mobile }}

Email

{{ viewingApp.guardian_email }}

Emergency Contact

Name

{{ viewingApp.emergency_name }}

Mobile

{{ viewingApp.emergency_mobile }}

Participants ({{ viewingApp.num_participants }})

{{ idx + 1 }}

{{ p.name }}

Age: {{ p.age }} · Gender: {{ p.gender }}

Payment Details

Registration Fee

RM {{ parseFloat(Number(viewingApp.total_fee) + Number(viewingApp.voucher_discount || 0)) }}

Voucher Discount

− RM {{ parseFloat(viewingApp.voucher_discount) }} ({{ viewingApp.voucher_code }})

{{ viewingApp.voucher_discount > 0 ? 'Amount Due' : 'Registration Fee' }}

RM

AI Detected Amount

{{ viewingApp.extracted_amount || '-' }}

Payment Evidence

No evidence uploaded

How Did They Hear About Us

{{ s }}

Submitted At

{{ viewingApp.created_at }}

Last Updated

{{ viewingApp.updated_at }}

Admin Notes

+ New Registration

Parent / Guardian *

Emergency Contact *

Participants ({{ newReg.participants.length }})

{{ idx + 1 }}

Auto: RM {{ newRegAutoFee }}

{{ addRegError }}

Participants

🔍
✅ Check In 🎙 Interview

{{ filteredParticipants.length }}

Total

{{ filteredParticipants.filter(p=>Number(p.checked_in)).length }}

Checked In

{{ filteredParticipants.filter(p=>p.interview_story).length }}

Interviewed

{{ filteredParticipants.filter(p=>p.cartoon_image_path||p.creation_image_path).length }}

Wallpapers

{{ filteredParticipants.filter(p=>Number(p.is_active)===0).length }}

Deactivated

# Participant Workshop Date Guardian Check-in Active Actions
{{ p.id }}
{{ (p.name||'?')[0] }}
{{ p.name }}
{{ p.age }} yrs · {{ p.gender||'—' }} {{ p.app_status }}
{{ dayOfWeek(p.workshop_date) }} {{ p.workshop_date }} N/A
{{ p.guardian_name }}
{{ p.guardian_mobile }}
👁️
No participants found

Workshop Dates

IDDayDateTimeMax SeatsActiveActions
{{ d.id }} {{ dayOfWeek(d.workshop_date) || '—' }}

Add Workshop Date

📅 {{ dayOfWeek(newDate.workshop_date) }}

Schedule Management

📋 Copy Schedule From Another Date

{{ item.icon }} {{ item.time_slot }} {{ item.title_en }}

English

Chinese

Malay

Tamil

No schedule items for this date. Use "Copy From..." to clone from another date, or add items manually.

Add Schedule Item

English

Chinese

Malay

Tamil

Pricing Management

{{ p.num_participants }} {{ p.num_participants>1?'participants':'participant' }}
RM

Voucher Codes

Create discount voucher codes for registrants. Set discount (RM) per participant count. Enter 0 = no discount for that tier. Max Uses = 0 means unlimited.

RM RM{{ getBasePrice(t) }} → RM{{ getDiscountedPrice(t, newVoucher['discount_'+t]) }}
Code Discount → Final Price Description Uses Status
{{ v.code }}
{{ t }}p: RM{{ getBasePrice(t) }} → RM{{ getDiscountedPrice(t, v['discount_'+t]) }} (−RM{{ Number(v['discount_'+t]).toFixed(0) }})
{{ v.description || '—' }} {{ v.used_count }}/{{ v.max_uses==0?'∞':v.max_uses }}
No voucher codes yet

Edit Voucher: {{ editingVoucher.code }}

RM → RM{{ getDiscountedPrice(t, editingVoucher['discount_'+t]) }}

🔐 Face Recognition Strictness

Control how strict the face scan must be before granting station access. A stricter setting requires a closer match but reduces false identifications.

{{currentFaceModeInfo.icon}} {{currentFaceModeInfo.label}} Mode
{{currentFaceModeInfo.desc}}
Threshold: {{currentFaceModeInfo.threshold}}
Frames: {{currentFaceModeInfo.frames}}
Gap: {{currentFaceModeInfo.gap}}
Loading...
Saved! Stations will use this mode on next scan.

🔑 Change Password

Workshop App — Step Timer Settings

#Step NameTime Limit (min)
{{ i + 1 }} {{ STEP_LABELS[s.step_key] || s.step_key }}
{{ activityLogModal.participant?.name }}
⏱ Checked in: {{ formatLogTime(activityLogModal.participant.checked_in_at) }} 📧 {{ activityLogModal.participant.guardian_email }}
S{{ s }} {{ activityLogModal.participant?.['station_'+s+'_start_at'] ? formatLogTime(activityLogModal.participant['station_'+s+'_start_at']) : '--' }}
Loading activity log...
No activity recorded yet.
# TIME ELAPSED STATION TASK ACTION PTS
{{ li+1 }} {{ formatLogTime(log.created_at) }} {{ logElapsed(activityLogModal.participant?.checked_in_at, log.created_at) }} S{{ log.station }} {{ log.task_label }} {{ log.event_type==='delete' ? 'DELETED' : log.event_type==='modify' ? 'MODIFIED' : log.task_key?.includes('_start') ? 'ARRIVED' : 'COMPLETED' }} {{ log.event_type==='delete' && log.points > 0 ? '-'+log.points : log.points > 0 ? '+'+log.points : '' }}
{{ activityLogModal.logs.length }} events recorded