-project ux (ux for user role)
This commit is contained in:
@@ -52,7 +52,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-end pt-4">
|
<div class="flex justify-end pt-4">
|
||||||
<button (click)="goToStep(2)" class="px-8 py-2.5 bg-gradient-to-r from-red-500 to-red-600 text-white font-semibold rounded-lg shadow-md hover:shadow-lg hover:from-red-600 hover:to-red-700 transform hover:-translate-y-0.5 transition-all duration-200">
|
<button (click)="goToStep(2)" class="px-8 py-2.5 bg-linear-to-r from-red-500 to-red-600 text-white font-semibold rounded-lg shadow-md hover:shadow-lg hover:from-red-600 hover:to-red-700 transform hover:-translate-y-0.5 transition-all duration-200">
|
||||||
ถัดไป <i class="fas fa-arrow-right ml-2"></i>
|
ถัดไป <i class="fas fa-arrow-right ml-2"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -110,7 +110,7 @@
|
|||||||
<button (click)="goToStep(1)" class="px-6 py-2.5 text-gray-600 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 font-medium transition-colors">
|
<button (click)="goToStep(1)" class="px-6 py-2.5 text-gray-600 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 font-medium transition-colors">
|
||||||
ย้อนกลับ
|
ย้อนกลับ
|
||||||
</button>
|
</button>
|
||||||
<button (click)="goToStep(3)" class="px-8 py-2.5 bg-gradient-to-r from-red-500 to-red-600 text-white font-semibold rounded-lg shadow-md hover:shadow-lg hover:from-red-600 hover:to-red-700 transform hover:-translate-y-0.5 transition-all duration-200">
|
<button (click)="goToStep(3)" class="px-8 py-2.5 bg-linear-to-r from-red-500 to-red-600 text-white font-semibold rounded-lg shadow-md hover:shadow-lg hover:from-red-600 hover:to-red-700 transform hover:-translate-y-0.5 transition-all duration-200">
|
||||||
ตรวจสอบข้อมูล <i class="fas fa-arrow-right ml-2"></i>
|
ตรวจสอบข้อมูล <i class="fas fa-arrow-right ml-2"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit, Output, EventEmitter } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
|
||||||
import { FormGroup, FormControl, Validators } from '@angular/forms';
|
import { FormGroup, FormControl, Validators } from '@angular/forms';
|
||||||
import { GeneralService } from '../../services/generalservice';
|
|
||||||
import { ToastrService } from 'ngx-toastr';
|
import { ToastrService } from 'ngx-toastr';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -11,17 +9,17 @@ import { ToastrService } from 'ngx-toastr';
|
|||||||
styleUrl: './main-project-add.css',
|
styleUrl: './main-project-add.css',
|
||||||
})
|
})
|
||||||
export class MainProjectAdd implements OnInit {
|
export class MainProjectAdd implements OnInit {
|
||||||
currentStep: number = 1;
|
// ไม่ต้องใช้ @Input() แล้ว Parent จะเข้าถึงผ่าน ViewChild
|
||||||
isLoading: boolean = false;
|
isLoading: boolean = false;
|
||||||
|
|
||||||
|
@Output() save = new EventEmitter<any>();
|
||||||
|
@Output() cancel = new EventEmitter<void>();
|
||||||
|
|
||||||
|
currentStep: number = 1;
|
||||||
projectForm!: FormGroup;
|
projectForm!: FormGroup;
|
||||||
attachedFiles: any[] = [];
|
attachedFiles: any[] = [];
|
||||||
|
|
||||||
constructor(
|
constructor(private toastr: ToastrService) {}
|
||||||
private generalService: GeneralService,
|
|
||||||
private router: Router,
|
|
||||||
private toastr: ToastrService
|
|
||||||
) {}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.setupFormControl();
|
this.setupFormControl();
|
||||||
@@ -34,9 +32,7 @@ export class MainProjectAdd implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ฟังก์ชันเปลี่ยน Step (เรียกใช้จากปุ่มเท่านั้น)
|
|
||||||
goToStep(step: number): void {
|
goToStep(step: number): void {
|
||||||
// กรณีจะไป Step 2 ต้องผ่าน Validation Step 1 ก่อน
|
|
||||||
if (step === 2 && this.currentStep === 1) {
|
if (step === 2 && this.currentStep === 1) {
|
||||||
if (this.projectForm.invalid) {
|
if (this.projectForm.invalid) {
|
||||||
this.projectForm.markAllAsTouched();
|
this.projectForm.markAllAsTouched();
|
||||||
@@ -70,9 +66,7 @@ export class MainProjectAdd implements OnInit {
|
|||||||
this.attachedFiles.splice(index, 1);
|
this.attachedFiles.splice(index, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
get f() {
|
get f() { return this.projectForm.controls; }
|
||||||
return this.projectForm.controls;
|
|
||||||
}
|
|
||||||
|
|
||||||
formatCurrency(amount: any): string {
|
formatCurrency(amount: any): string {
|
||||||
if (!amount) return '0.00 บาท';
|
if (!amount) return '0.00 บาท';
|
||||||
@@ -82,27 +76,15 @@ export class MainProjectAdd implements OnInit {
|
|||||||
onSubmit(): void {
|
onSubmit(): void {
|
||||||
if (this.projectForm.invalid) return;
|
if (this.projectForm.invalid) return;
|
||||||
|
|
||||||
this.isLoading = true;
|
const body = {
|
||||||
const uri = '/api/project/create';
|
|
||||||
|
|
||||||
const request = {
|
|
||||||
...this.projectForm.value,
|
...this.projectForm.value,
|
||||||
files: this.attachedFiles
|
files: this.attachedFiles
|
||||||
};
|
};
|
||||||
|
|
||||||
this.generalService.postRequest(uri, request).subscribe({
|
this.save.emit(body);
|
||||||
next: (result: any) => {
|
}
|
||||||
this.isLoading = false;
|
|
||||||
this.generalService.trowApi(result);
|
|
||||||
|
|
||||||
if (result.code === '200') {
|
onCancel(): void {
|
||||||
this.router.navigate(['/main']);
|
this.cancel.emit();
|
||||||
}
|
|
||||||
},
|
|
||||||
error: (error: any) => {
|
|
||||||
this.isLoading = false;
|
|
||||||
this.generalService.trowApi(error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,115 +1,53 @@
|
|||||||
<div class="h-screen bg-gray-100 flex flex-col">
|
<div class="h-screen bg-gray-100 flex flex-col">
|
||||||
|
|
||||||
<header class="flex justify-between items-center py-4 px-6">
|
<!-- Header Section -->
|
||||||
|
<header class="flex justify-between items-center py-4 px-6 bg-white shadow-sm border-b border-gray-200 z-10">
|
||||||
@if (mode == 'default') {
|
@if (mode == 'default') {
|
||||||
<h1 class="text-3xl font-bold text-gray-800">โครงการทั้งหมด</h1>
|
<h1 class="text-2xl font-bold text-gray-800 flex items-center gap-2">
|
||||||
|
<i class="fas fa-folder text-red-500"></i> โครงการทั้งหมด
|
||||||
|
</h1>
|
||||||
} @else if (mode == 'add') {
|
} @else if (mode == 'add') {
|
||||||
<h1 class="text-3xl font-bold text-gray-800">เพิ่มโครงการ</h1>
|
<div class="flex items-center gap-3">
|
||||||
|
<!-- ปุ่มย้อนกลับ -->
|
||||||
|
<button (click)="onCancelProject()"
|
||||||
|
class="w-10 h-10 rounded-full flex items-center justify-center hover:bg-gray-100 text-gray-500 transition-colors hover:text-red-500"
|
||||||
|
title="ย้อนกลับ">
|
||||||
|
<i class="fas fa-arrow-left text-lg"></i>
|
||||||
|
</button>
|
||||||
|
<h1 class="text-2xl font-bold text-gray-800 flex items-center gap-2">
|
||||||
|
<i class="fas fa-plus-circle text-red-500"></i> เพิ่มโครงการ
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
} @else if (mode == 'edit') {
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<!-- ปุ่มย้อนกลับ -->
|
||||||
|
<button (click)="onCancelProject()"
|
||||||
|
class="w-10 h-10 rounded-full flex items-center justify-center hover:bg-gray-100 text-gray-500 transition-colors hover:text-red-500"
|
||||||
|
title="ย้อนกลับ">
|
||||||
|
<i class="fas fa-arrow-left text-lg"></i>
|
||||||
|
</button>
|
||||||
|
<h1 class="text-2xl font-bold text-gray-800 flex items-center gap-2">
|
||||||
|
<i class="fas fa-edit text-red-500"></i> แก้ไขโครงการ
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div class="grow overflow-y-auto px-6 pb-6">
|
<!-- Content Area (Scrollable) -->
|
||||||
|
<div class="grow overflow-y-auto px-6 pb-6 pt-6">
|
||||||
|
|
||||||
@if ( mode == 'default') {
|
@if ( mode == 'default') {
|
||||||
|
<!-- รายการโครงการ (Smart Component ย่อย หรือ Dumb Component ก็ได้) -->
|
||||||
<app-main-project></app-main-project>
|
<app-main-project></app-main-project>
|
||||||
|
|
||||||
} @else if ( mode == 'add') {
|
} @else if ( mode == 'add') {
|
||||||
<app-main-project-add></app-main-project-add>
|
<!-- หน้าเพิ่มโครงการ (Dumb Component) -->
|
||||||
|
<!-- เชื่อม Event save/cancel กลับมาที่ Parent -->
|
||||||
|
<app-main-project-add
|
||||||
|
(save)="onSaveProject($event)"
|
||||||
|
(cancel)="onCancelProject()">
|
||||||
|
</app-main-project-add>
|
||||||
}
|
}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <div class="h-screen bg-gray-100 flex flex-col">
|
|
||||||
|
|
||||||
<header class="flex justify-between items-center py-4 px-6 bg-white shadow-sm shrink-0 z-10">
|
|
||||||
<h1 class="text-2xl font-bold text-gray-800">
|
|
||||||
{{ mode === 'add' ? 'สร้างโครงการใหม่' : 'โครงการทั้งหมด' }}
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<button *ngIf="mode === 'default'"
|
|
||||||
(click)="mode = 'add'"
|
|
||||||
class="bg-red-500 hover:bg-red-600 text-white px-4 py-2 rounded-lg shadow-sm text-sm font-medium transition">
|
|
||||||
+ เพิ่มโครงการ
|
|
||||||
</button>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="grow overflow-y-auto p-6">
|
|
||||||
|
|
||||||
@if (mode === 'default') {
|
|
||||||
<app-main-project></app-main-project>
|
|
||||||
|
|
||||||
} @else if (mode === 'add') {
|
|
||||||
|
|
||||||
<div class="flex items-start justify-center min-h-full">
|
|
||||||
<div class="bg-white p-8 rounded-xl shadow-lg w-full max-w-lg border border-gray-100">
|
|
||||||
|
|
||||||
<div class="flex justify-between items-center mb-6">
|
|
||||||
<h2 class="text-xl font-bold text-gray-800">รายละเอียดโครงการ</h2>
|
|
||||||
<button (click)="mode = 'default'" class="text-gray-400 hover:text-gray-600">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form class="space-y-5"> <div>
|
|
||||||
<label for="projectName" class="block text-sm font-medium text-gray-700 mb-1">ชื่อโครงการ</label>
|
|
||||||
<input type="text" id="projectName" name="projectName"
|
|
||||||
class="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-red-500 focus:border-red-500 outline-none transition shadow-sm"
|
|
||||||
placeholder="ป้อนชื่อโครงการ">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label for="budgetType" class="block text-sm font-medium text-gray-700 mb-1">ประเภทงบประมาณ</label>
|
|
||||||
<div class="relative">
|
|
||||||
<select id="budgetType" name="budgetType"
|
|
||||||
class="w-full p-3 bg-white border border-gray-300 rounded-lg focus:ring-2 focus:ring-red-500 focus:border-red-500 outline-none appearance-none shadow-sm cursor-pointer">
|
|
||||||
<option value="">-- เลือกประเภท --</option>
|
|
||||||
<option value="operation">งบดำเนินงาน</option>
|
|
||||||
<option value="investment">งบลงทุน</option>
|
|
||||||
<option value="research">งบวิจัย</option>
|
|
||||||
</select>
|
|
||||||
<div class="absolute inset-y-0 right-0 flex items-center px-3 pointer-events-none text-gray-500">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label for="amount" class="block text-sm font-medium text-gray-700 mb-1">จำนวนเงิน (บาท)</label>
|
|
||||||
<input type="number" id="amount" name="amount"
|
|
||||||
class="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-red-500 focus:border-red-500 outline-none transition shadow-sm"
|
|
||||||
placeholder="เช่น 15000.00">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label for="date" class="block text-sm font-medium text-gray-700 mb-1">วันที่เริ่มโครงการ</label>
|
|
||||||
<div class="relative">
|
|
||||||
<input type="date" id="date" name="date"
|
|
||||||
class="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-red-500 focus:border-red-500 outline-none transition shadow-sm text-gray-700">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center gap-3 pt-4">
|
|
||||||
<button type="button" (click)="mode = 'default'"
|
|
||||||
class="flex-1 px-4 py-3 bg-gray-100 text-gray-700 font-semibold rounded-lg hover:bg-gray-200 transition">
|
|
||||||
ยกเลิก
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button type="submit"
|
|
||||||
class="flex-1 px-4 py-3 bg-red-500 text-white font-semibold rounded-lg shadow-md hover:bg-red-600 focus:ring-2 focus:ring-offset-2 focus:ring-red-500 transition">
|
|
||||||
ส่งโครงการ
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div> -->
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Routes, Router, ActivatedRoute } from '@angular/router';
|
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { GeneralService } from '../../services/generalservice';
|
||||||
|
import { MainProjectAdd } from '../../component/main-project-add/main-project-add'; // Import Dumb Component
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-main-project-content',
|
selector: 'app-main-project-content',
|
||||||
@@ -9,22 +10,63 @@ import { Component, OnInit } from '@angular/core';
|
|||||||
styleUrl: './main-project-content.css',
|
styleUrl: './main-project-content.css',
|
||||||
})
|
})
|
||||||
export class MainProjectContent implements OnInit {
|
export class MainProjectContent implements OnInit {
|
||||||
|
// เข้าถึง Component ลูกเพื่อสั่ง Loading
|
||||||
|
@ViewChild(MainProjectAdd) mainProjectAdd!: MainProjectAdd;
|
||||||
|
|
||||||
mode: 'add' | 'edit' | 'default' = 'default';
|
mode: 'add' | 'edit' | 'default' = 'default';
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private router: Router
|
private router: Router,
|
||||||
|
private generalService: GeneralService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
let param = this.route.snapshot.paramMap.get('mode');
|
// Subscribe paramMap เพื่อให้เปลี่ยน Mode ได้ทันทีถ้า URL เปลี่ยน
|
||||||
|
this.route.paramMap.subscribe(params => {
|
||||||
|
const modeParam = params.get('mode');
|
||||||
|
if (modeParam === 'add') {
|
||||||
|
this.mode = 'add';
|
||||||
|
} else if (modeParam === 'edit') {
|
||||||
|
this.mode = 'edit';
|
||||||
|
} else {
|
||||||
|
this.mode = 'default';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (param === 'add') {
|
// รับ Event (save) จากลูก แล้วยิง API
|
||||||
this.mode = 'add';
|
onSaveProject(projectData: any): void {
|
||||||
} else if (param === 'edit') {
|
// เปิด Loading ที่ลูก
|
||||||
this.mode = 'edit';
|
if (this.mainProjectAdd) {
|
||||||
} else {
|
this.mainProjectAdd.isLoading = true;
|
||||||
this.mode = 'default';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const uri = '/api/project/create'; // Endpoint Backend
|
||||||
|
|
||||||
|
this.generalService.postRequest(uri, projectData).subscribe({
|
||||||
|
next: (result: any) => {
|
||||||
|
// ปิด Loading ที่ลูก
|
||||||
|
if (this.mainProjectAdd) this.mainProjectAdd.isLoading = false;
|
||||||
|
|
||||||
|
this.generalService.trowApi(result);
|
||||||
|
|
||||||
|
if (result.code === '200') {
|
||||||
|
// สำเร็จ -> กลับไปหน้ารายการ
|
||||||
|
this.router.navigate(['/main/project']);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: (error: any) => {
|
||||||
|
// Error -> ปิด Loading ที่ลูก
|
||||||
|
if (this.mainProjectAdd) this.mainProjectAdd.isLoading = false;
|
||||||
|
|
||||||
|
this.generalService.trowApi(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// รับ Event (cancel) จากลูก
|
||||||
|
onCancelProject(): void {
|
||||||
|
this.router.navigate(['/main/project']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user