fix: update password update messages and handle invalid current password error

This commit is contained in:
sudomarcma
2025-09-10 16:06:19 +08:00
parent e24a704732
commit 4bad24ab76
4 changed files with 123 additions and 14 deletions
+107
View File
@@ -0,0 +1,107 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
NiLai-Clock is a worker attendance management system with role-based dashboards for workers and managers. It's built as a Vue.js SPA with an Express.js backend, featuring QR code attendance tracking, geofencing, and comprehensive reporting capabilities.
## Commands
### Development
- `npm run dev` - Start frontend development server (Vite on port 5173)
- `npm run backend` - Start backend server (Express on port 3000)
- `npm run dev:all` - Run both frontend and backend concurrently
- `npm install` - Install dependencies
### Production
- `npm run build` - Build for production using Vite
- `npm run preview` - Preview production build locally
### Code Quality
- `npm run lint` - Run ESLint with auto-fix
- `npm run format` - Format code using Prettier
## Architecture
### Frontend (Vue.js)
- **Framework**: Vue 3 with Composition API
- **Build Tool**: Vite with Vue plugin and TailwindCSS
- **Routing**: Vue Router with hash-based routing and role-based guards
- **State**: Session storage for authentication (userId, userRole, token)
- **Styling**: TailwindCSS v4 with responsive design
- **Internationalization**: Vue I18n with English (en) and Malay (ms) locales
### Backend (Express.js)
- **Server**: Express with CORS, supports both HTTP and HTTPS
- **Database**: MySQL with connection pooling (mysql2)
- **Authentication**: JWT tokens with bcrypt for password hashing
- **Routes**: Separated into manager (`/api/managers/*`) and worker (`/api/*`) routes
### Key Components Structure
#### Views (Role-Based)
- **Worker**: `WorkerDashboard`, `WorkerHistory`, `WorkerSettings`, `WorkerChangePassword`
- **Manager**: `ManagerDashboard`, `ManagerAttendanceRecord`
- **Auth**: `Login` (supports both roles)
#### Components
- **Management**: `PersonnelManagement`, `GeofenceManagement`, `QrCodeManagement`, `KillSwitchManagement`
- **UI**: `Toast` notifications with `useToast` composable
- **Reporting**: `WarningReporting` with CSV export capabilities
### Authentication Flow
- Role-based routing with `meta: { requiresAuth: true, role: 'worker|manager' }`
- Navigation guards redirect users to appropriate dashboards
- Session storage manages authentication state
- API requests include JWT tokens via Authorization header
### Key Libraries
- **Maps**: Leaflet with drawing capabilities for geofencing
- **QR Codes**: html5-qrcode for scanning, qrcode for generation
- **Geospatial**: @turf/turf for geographical calculations
- **Data Export**: json2csv for attendance reports
- **UUID**: For device identification and worker login tracking
## Environment Configuration
Create `.env` file with:
```
DB_HOST=your_database_host
DB_USER=your_database_user
DB_PASSWORD=your_database_password
DB_NAME=your_database_name
DB_PORT=your_database_port
VITE_API_BASE_URL=your_api_base_url
```
Optional SSL configuration:
- `SSL_ENABLED=true`
- `HTTP_PORT=3000`
- `HTTPS_PORT=3443`
## Development Notes
- Frontend uses hash-based routing for better deployment compatibility
- Backend supports both HTTP and HTTPS with configurable ports
- CORS configured for multiple origins including mobile app protocols
- Database connection is tested on server startup with proper error handling
- All API calls go through centralized `apiFetch` utility with error handling
- ESLint configured to ignore unused variables/parameters prefixed with underscore
- Prettier integrated with Vue ESLint config for consistent formatting
## Database Schema
The application manages worker attendance with these core entities:
- **Workers**: Authentication, device UUID tracking, role assignment
- **Managers**: Administrative access and permissions
- **Attendance Records**: Clock in/out with location and timestamp data
- **Geofences**: Location boundaries for valid attendance tracking
- **QR Codes**: Dynamic codes for attendance verification
## Docker Support
Includes Docker configuration:
- `Dockerfile` - Node.js Alpine-based container
- `docker-compose.yml` - Multi-service setup with nginx reverse proxy
- Production deployment on port 18080 (nginx) and 18081 (app)
+2 -1
View File
@@ -81,8 +81,9 @@
"updatePassword": "Update Password",
"passwordsNoMatch": "New passwords do not match.",
"passwordTooShort": "New password must be at least 6 characters long.",
"passwordUpdated": "Password updated successfully! You can now use your new password to log in.",
"passwordUpdated": "Password updated successfully!",
"passwordUpdateError": "An error occurred while updating the password.",
"invalidCurrentPassword": "The current password you entered is incorrect.",
"attendanceLogFor": "Attendance Log for",
"addManualClockOut": "Add Manual Clock-Out",
+2 -1
View File
@@ -82,8 +82,9 @@
"updatePassword": "Kemaskini Kata Laluan",
"passwordsNoMatch": "Kata laluan baharu tidak sepadan.",
"passwordTooShort": "Kata laluan baharu mesti sekurang-kurangnya 6 aksara.",
"passwordUpdated": "Kata laluan berjaya dikemaskini! Anda boleh guna kata laluan baharu untuk log masuk.",
"passwordUpdated": "Kata laluan berjaya dikemaskini!",
"passwordUpdateError": "Ralat semasa mengemaskini kata laluan.",
"invalidCurrentPassword": "Kata laluan semasa yang anda masukkan tidak betul.",
"attendanceLogFor": "Log Kehadiran untuk",
"addManualClockOut": "Tambah Clock-Out Secara Manual",
+12 -12
View File
@@ -84,7 +84,7 @@ const handleChangePassword = async () => {
loading.value = true
try {
const response = await apiFetch('/api/worker/change-password', {
await apiFetch('/api/worker/change-password', {
method: 'PUT',
body: JSON.stringify({
currentPassword: passwords.value.currentPassword,
@@ -92,20 +92,20 @@ const handleChangePassword = async () => {
}),
})
if (!response.ok) {
const errorData = await response.json()
if (response.status === 401) {
errorMessage.value = 'invalidCurrentPassword'
} else {
errorMessage.value = errorData.message || 'passwordUpdateError'
}
return
}
// apiFetch already handles response parsing and throws errors for non-200 status
// If we reach here, the request was successful
successMessage.value = 'passwordUpdated'
passwords.value = { currentPassword: '', newPassword: '', confirmPassword: '' }
} catch (err) {
errorMessage.value = err.message || 'passwordUpdateError'
// Handle specific error cases based on the error message from server
if (err.message.includes('Incorrect current password') || err.message.includes('401')) {
errorMessage.value = 'invalidCurrentPassword'
} else if (err.message.includes('Invalid input')) {
errorMessage.value = 'passwordUpdateError'
} else {
// For any other errors, use the generic error message
errorMessage.value = 'passwordUpdateError'
}
} finally {
loading.value = false
}