feat: Implement core user profile, dashboard, course browsing pages, common components, and internationalization.
This commit is contained in:
parent
01978f9438
commit
11d714c632
10 changed files with 289 additions and 99 deletions
|
|
@ -163,13 +163,13 @@ const saveProfile = async () => {
|
|||
<div class="profile-page max-w-4xl mx-auto px-4 py-8">
|
||||
<!-- Header: Title and Edit action -->
|
||||
<div class="flex items-center justify-between mb-10">
|
||||
<h1 class="text-3xl font-black text-slate-900 dark:text-white">โปรไฟล์ของฉัน</h1>
|
||||
<h1 class="text-3xl font-black text-slate-900 dark:text-white">{{ $t('profile.myProfile') }}</h1>
|
||||
<div class="flex items-center gap-6">
|
||||
<button v-if="!isEditing" class="btn-premium-edit" @click="toggleEdit(true)">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
|
||||
</svg>
|
||||
แก้ไขโปรไฟล์
|
||||
{{ $t('profile.editProfile') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -200,15 +200,15 @@ const saveProfile = async () => {
|
|||
<!-- Info Grid -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||
<div class="info-group">
|
||||
<span class="label">อีเมล</span>
|
||||
<span class="label">{{ $t('profile.email') }}</span>
|
||||
<p class="value">{{ userData.email }}</p>
|
||||
</div>
|
||||
<div class="info-group">
|
||||
<span class="label">เบอร์โทรศัพท์</span>
|
||||
<span class="label">{{ $t('profile.phone') }}</span>
|
||||
<p class="value">{{ userData.phone }}</p>
|
||||
</div>
|
||||
<div class="info-group">
|
||||
<span class="label">สมัครสมาชิกเมื่อ</span>
|
||||
<span class="label">{{ $t('profile.joinedAt') }}</span>
|
||||
<p class="value">{{ userData.createdAt }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -224,7 +224,7 @@ const saveProfile = async () => {
|
|||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
||||
</svg>
|
||||
</button>
|
||||
<h2 class="text-2xl font-black text-slate-900 dark:text-white">แก้ไขข้อมูลส่วนตัว</h2>
|
||||
<h2 class="text-2xl font-black text-slate-900 dark:text-white">{{ $t('profile.editPersonalDesc') }}</h2>
|
||||
</div>
|
||||
|
||||
<!-- Avatar Upload Section -->
|
||||
|
|
@ -246,16 +246,16 @@ const saveProfile = async () => {
|
|||
<input ref="fileInput" type="file" class="hidden" accept="image/*" @change="handleFileUpload" >
|
||||
</div>
|
||||
<div class="text-center md:text-left">
|
||||
<h3 class="font-black text-slate-900 dark:text-white mb-2">รูปโปรไฟล์ของคุณ</h3>
|
||||
<p class="text-xs text-slate-500 mb-4 uppercase tracking-widest font-bold">เฉพาะไฟล์ png , jpg</p>
|
||||
<button class="btn-upload" @click="triggerUpload">อัปโหลดรูปใหม่</button>
|
||||
<h3 class="font-black text-slate-900 dark:text-white mb-2">{{ $t('profile.yourAvatar') }}</h3>
|
||||
<p class="text-xs text-slate-500 mb-4 uppercase tracking-widest font-bold">{{ $t('profile.avatarHint') }}</p>
|
||||
<button class="btn-upload" @click="triggerUpload">{{ $t('profile.uploadNew') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Form Inputs -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-10">
|
||||
<div class="space-y-2">
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-500 dark:text-slate-300">คำนำหน้า</label>
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-500 dark:text-slate-300">{{ $t('profile.prefix') }}</label>
|
||||
<select v-model="userData.prefix" class="premium-input w-full">
|
||||
<option>นาย</option>
|
||||
<option>นาง</option>
|
||||
|
|
@ -264,7 +264,7 @@ const saveProfile = async () => {
|
|||
</div>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div class="space-y-2">
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-500 dark:text-slate-300">ชื่อ</label>
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-500 dark:text-slate-300">{{ $t('profile.firstName') }}</label>
|
||||
<input
|
||||
v-model="userData.firstName"
|
||||
type="text"
|
||||
|
|
@ -275,7 +275,7 @@ const saveProfile = async () => {
|
|||
<span v-if="errors.firstName" class="text-red-500 text-[10px] mt-1 font-bold">{{ errors.firstName }}</span>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-500 dark:text-slate-300">นามสกุล</label>
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-500 dark:text-slate-300">{{ $t('profile.lastName') }}</label>
|
||||
<input
|
||||
v-model="userData.lastName"
|
||||
type="text"
|
||||
|
|
@ -287,7 +287,7 @@ const saveProfile = async () => {
|
|||
</div>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-500 dark:text-slate-300">อีเมล</label>
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-500 dark:text-slate-300">{{ $t('profile.email') }}</label>
|
||||
<input
|
||||
v-model="userData.email"
|
||||
type="email"
|
||||
|
|
@ -298,7 +298,7 @@ const saveProfile = async () => {
|
|||
<span v-if="errors.email" class="text-red-500 text-[10px] mt-1 font-bold">{{ errors.email }}</span>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-500 dark:text-slate-300">เบอร์โทรศัพท์</label>
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-500 dark:text-slate-300">{{ $t('profile.phone') }}</label>
|
||||
<input
|
||||
v-model="userData.phone"
|
||||
type="text"
|
||||
|
|
@ -312,10 +312,10 @@ const saveProfile = async () => {
|
|||
|
||||
<!-- Security Section -->
|
||||
<div class="border-t border-slate-200 dark:border-white/5 pt-10 mb-10">
|
||||
<h3 class="text-lg font-black text-slate-900 dark:text-white mb-6">ความปลอดภัย</h3>
|
||||
<h3 class="text-lg font-black text-slate-900 dark:text-white mb-6">{{ $t('profile.security') }}</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div class="space-y-2">
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-500 dark:text-slate-300">รหัสผ่านปัจจุบัน</label>
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-500 dark:text-slate-300">{{ $t('profile.currentPassword') }}</label>
|
||||
<div class="relative">
|
||||
<input
|
||||
v-model="passwordForm.currentPassword"
|
||||
|
|
@ -340,7 +340,7 @@ const saveProfile = async () => {
|
|||
</div>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-500 dark:text-slate-300">รหัสผ่านใหม่</label>
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-500 dark:text-slate-300">{{ $t('profile.newPassword') }}</label>
|
||||
<div class="relative">
|
||||
<input
|
||||
v-model="passwordForm.newPassword"
|
||||
|
|
@ -367,7 +367,7 @@ const saveProfile = async () => {
|
|||
<span v-if="errors.newPassword" class="text-red-500 text-[10px] mt-1 font-bold">{{ errors.newPassword }}</span>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-500 dark:text-slate-300">ยืนยันรหัสผ่านใหม่</label>
|
||||
<label class="text-xs font-black uppercase tracking-widest text-slate-500 dark:text-slate-300">{{ $t('profile.confirmNewPassword') }}</label>
|
||||
<div class="relative">
|
||||
<input
|
||||
v-model="passwordForm.confirmPassword"
|
||||
|
|
@ -398,8 +398,8 @@ const saveProfile = async () => {
|
|||
|
||||
<!-- Actions -->
|
||||
<div class="flex flex-col md:flex-row gap-4 pt-6 border-t border-white/5">
|
||||
<button class="btn-save-premium flex-1" @click="saveProfile">บันทึกข้อมูล</button>
|
||||
<button class="btn-cancel-premium md:w-32" @click="toggleEdit(false)">ยกเลิก</button>
|
||||
<button class="btn-save-premium flex-1" @click="saveProfile">{{ $t('save') }}</button>
|
||||
<button class="btn-cancel-premium md:w-32" @click="toggleEdit(false)">{{ $t('cancel') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue