Merge pull request 'feat: add active status management for academic terms, users, and students with new UpdateStatusRequest' (#52) from feat/add-status-management-academic-terms into dev
Reviewed-on: itm/siakad-itm#52
This commit is contained in:
commit
b76d82c2f0
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\Admin\Master\AcademicTermRequest;
|
use App\Http\Requests\Admin\Master\AcademicTermRequest;
|
||||||
|
use App\Http\Requests\Admin\UpdateStatusRequest;
|
||||||
use App\Http\Requests\PaginatedRequest;
|
use App\Http\Requests\PaginatedRequest;
|
||||||
use App\Models\AcademicTerm;
|
use App\Models\AcademicTerm;
|
||||||
use App\Services\Admin\Master\AcademicTermService;
|
use App\Services\Admin\Master\AcademicTermService;
|
||||||
@ -53,4 +54,11 @@ public function destroy(AcademicTerm $academicTerm): RedirectResponse
|
|||||||
|
|
||||||
return Inertia::flash('toast', ['type' => 'success', 'message' => 'Periode akademik berhasil dihapus.'])->back();
|
return Inertia::flash('toast', ['type' => 'success', 'message' => 'Periode akademik berhasil dihapus.'])->back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function updateStatus(UpdateStatusRequest $request, AcademicTerm $academicTerm): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->service->updateActiveStatus($academicTerm, $request->boolean('is_active'));
|
||||||
|
|
||||||
|
return Inertia::flash('toast', ['type' => 'success', 'message' => 'Status periode akademik berhasil diperbarui.'])->back();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,8 +3,8 @@
|
|||||||
namespace App\Http\Controllers\Admin\Users;
|
namespace App\Http\Controllers\Admin\Users;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\Admin\UpdateStatusRequest;
|
||||||
use App\Http\Requests\Admin\Users\AdministratorRequest;
|
use App\Http\Requests\Admin\Users\AdministratorRequest;
|
||||||
use App\Http\Requests\Admin\Users\UpdateUserStatusRequest;
|
|
||||||
use App\Http\Requests\PaginatedRequest;
|
use App\Http\Requests\PaginatedRequest;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Services\Admin\Users\AdministratorService;
|
use App\Services\Admin\Users\AdministratorService;
|
||||||
@ -79,7 +79,7 @@ public function resetPassword(User $user): RedirectResponse
|
|||||||
return Inertia::flash('toast', ['type' => 'success', 'message' => 'Kata sandi berhasil direset.'])->back();
|
return Inertia::flash('toast', ['type' => 'success', 'message' => 'Kata sandi berhasil direset.'])->back();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateUserStatus(UpdateUserStatusRequest $request, User $user): RedirectResponse
|
public function updateUserStatus(UpdateStatusRequest $request, User $user): RedirectResponse
|
||||||
{
|
{
|
||||||
$this->service->updateUserStatus($user, $request->boolean('is_active'));
|
$this->service->updateUserStatus($user, $request->boolean('is_active'));
|
||||||
|
|
||||||
|
|||||||
@ -4,8 +4,8 @@
|
|||||||
|
|
||||||
use App\Exports\LecturersExport;
|
use App\Exports\LecturersExport;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\Admin\UpdateStatusRequest;
|
||||||
use App\Http\Requests\Admin\Users\LecturerRequest;
|
use App\Http\Requests\Admin\Users\LecturerRequest;
|
||||||
use App\Http\Requests\Admin\Users\UpdateUserStatusRequest;
|
|
||||||
use App\Http\Requests\PaginatedRequest;
|
use App\Http\Requests\PaginatedRequest;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Services\Admin\Master\DepartmentService;
|
use App\Services\Admin\Master\DepartmentService;
|
||||||
@ -85,7 +85,7 @@ public function resetPassword(User $user): RedirectResponse
|
|||||||
return Inertia::flash('toast', ['type' => 'success', 'message' => 'Kata sandi berhasil direset.'])->back();
|
return Inertia::flash('toast', ['type' => 'success', 'message' => 'Kata sandi berhasil direset.'])->back();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateUserStatus(UpdateUserStatusRequest $request, User $user): RedirectResponse
|
public function updateUserStatus(UpdateStatusRequest $request, User $user): RedirectResponse
|
||||||
{
|
{
|
||||||
$this->service->updateUserStatus($user, $request->boolean('is_active'));
|
$this->service->updateUserStatus($user, $request->boolean('is_active'));
|
||||||
|
|
||||||
|
|||||||
@ -5,9 +5,9 @@
|
|||||||
use App\Enums\StudentStatus;
|
use App\Enums\StudentStatus;
|
||||||
use App\Exports\StudentsExport;
|
use App\Exports\StudentsExport;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\Admin\UpdateStatusRequest;
|
||||||
use App\Http\Requests\Admin\Users\Student\StudentRequest;
|
use App\Http\Requests\Admin\Users\Student\StudentRequest;
|
||||||
use App\Http\Requests\Admin\Users\Student\StudentStatusRequest;
|
use App\Http\Requests\Admin\Users\Student\StudentStatusRequest;
|
||||||
use App\Http\Requests\Admin\Users\UpdateUserStatusRequest;
|
|
||||||
use App\Http\Requests\PaginatedRequest;
|
use App\Http\Requests\PaginatedRequest;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Services\Admin\Master\DepartmentService;
|
use App\Services\Admin\Master\DepartmentService;
|
||||||
@ -100,7 +100,7 @@ public function updateStatus(StudentStatusRequest $request, User $user): Redirec
|
|||||||
return Inertia::flash('toast', ['type' => 'success', 'message' => 'Status mahasiswa berhasil diperbarui.'])->back();
|
return Inertia::flash('toast', ['type' => 'success', 'message' => 'Status mahasiswa berhasil diperbarui.'])->back();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateUserStatus(UpdateUserStatusRequest $request, User $user): RedirectResponse
|
public function updateUserStatus(UpdateStatusRequest $request, User $user): RedirectResponse
|
||||||
{
|
{
|
||||||
$this->service->updateUserStatus($user, $request->boolean('is_active'));
|
$this->service->updateUserStatus($user, $request->boolean('is_active'));
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Http\Requests\Admin\Users;
|
namespace App\Http\Requests\Admin;
|
||||||
|
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
class UpdateUserStatusRequest extends FormRequest
|
class UpdateStatusRequest extends FormRequest
|
||||||
{
|
{
|
||||||
public function authorize(): bool
|
public function authorize(): bool
|
||||||
{
|
{
|
||||||
@ -5,6 +5,7 @@
|
|||||||
use App\Models\AcademicTerm;
|
use App\Models\AcademicTerm;
|
||||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
class AcademicTermService
|
class AcademicTermService
|
||||||
{
|
{
|
||||||
@ -45,4 +46,15 @@ public function delete(AcademicTerm $academicTerm): bool
|
|||||||
{
|
{
|
||||||
return $academicTerm->delete();
|
return $academicTerm->delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function updateActiveStatus(AcademicTerm $academicTerm, bool $isActive): void
|
||||||
|
{
|
||||||
|
DB::transaction(function () use ($academicTerm, $isActive) {
|
||||||
|
if ($isActive) {
|
||||||
|
AcademicTerm::where('id', '!=', $academicTerm->id)->update(['is_active' => false]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$academicTerm->update(['is_active' => $isActive]);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,14 @@
|
|||||||
import { Switch } from '@/components/ui/switch';
|
import { Switch } from '@/components/ui/switch';
|
||||||
|
|
||||||
type UserActiveSwitchProps = {
|
type ActiveStatusSwitchProps = {
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
onChange: (isActive: boolean) => void;
|
onChange: (isActive: boolean) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function UserActiveSwitch({ isActive, onChange }: UserActiveSwitchProps) {
|
export function ActiveStatusSwitch({
|
||||||
|
isActive,
|
||||||
|
onChange,
|
||||||
|
}: ActiveStatusSwitchProps) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Switch checked={isActive} onCheckedChange={onChange} />
|
<Switch checked={isActive} onCheckedChange={onChange} />
|
||||||
@ -1,21 +1,23 @@
|
|||||||
import { RowActions } from '@/components/row-actions';
|
|
||||||
import { Badge } from '@/components/ui/badge';
|
|
||||||
import type { AcademicTerm } from '@/types/academic-term';
|
|
||||||
import { SemesterLabels, type Semester } from '@/types/academic-term';
|
|
||||||
import type { ColumnDef } from '@tanstack/react-table';
|
import type { ColumnDef } from '@tanstack/react-table';
|
||||||
import { Pencil, Trash2 } from 'lucide-react';
|
import { Pencil, Trash2 } from 'lucide-react';
|
||||||
|
import { ActiveStatusSwitch } from '@/components/active-status-switch';
|
||||||
|
import { RowActions } from '@/components/row-actions';
|
||||||
|
import { SemesterLabels } from '@/types/academic-term';
|
||||||
|
import type { AcademicTerm } from '@/types/academic-term';
|
||||||
|
import type { Semester } from '@/types/academic-term';
|
||||||
|
|
||||||
export type { AcademicTerm } from '@/types/academic-term';
|
export type { AcademicTerm } from '@/types/academic-term';
|
||||||
|
|
||||||
type CreateColumnsParams = {
|
type CreateColumnsParams = {
|
||||||
handleEdit: (academicTerm: AcademicTerm) => void;
|
handleEdit: (academicTerm: AcademicTerm) => void;
|
||||||
handleDeleteClick: (academicTerm: AcademicTerm) => void;
|
handleDeleteClick: (academicTerm: AcademicTerm) => void;
|
||||||
|
handleStatusChange: (academicTerm: AcademicTerm, isActive: boolean) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function createAcademicTermColumns(
|
export function createAcademicTermColumns(
|
||||||
params: CreateColumnsParams,
|
params: CreateColumnsParams,
|
||||||
): ColumnDef<AcademicTerm>[] {
|
): ColumnDef<AcademicTerm>[] {
|
||||||
const { handleEdit, handleDeleteClick } = params;
|
const { handleEdit, handleDeleteClick, handleStatusChange } = params;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@ -32,6 +34,7 @@ export function createAcademicTermColumns(
|
|||||||
header: () => <span>Semester</span>,
|
header: () => <span>Semester</span>,
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
const semester = row.getValue('semester') as Semester;
|
const semester = row.getValue('semester') as Semester;
|
||||||
|
|
||||||
return <span>{SemesterLabels[semester]}</span>;
|
return <span>{SemesterLabels[semester]}</span>;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -39,14 +42,18 @@ export function createAcademicTermColumns(
|
|||||||
accessorKey: 'formatted_start_date',
|
accessorKey: 'formatted_start_date',
|
||||||
header: () => <span>Tanggal Mulai</span>,
|
header: () => <span>Tanggal Mulai</span>,
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<span>{row.getValue('formatted_start_date') as string | null}</span>
|
<span>
|
||||||
|
{row.getValue('formatted_start_date') as string | null}
|
||||||
|
</span>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'formatted_end_date',
|
accessorKey: 'formatted_end_date',
|
||||||
header: () => <span>Tanggal Selesai</span>,
|
header: () => <span>Tanggal Selesai</span>,
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<span>{row.getValue('formatted_end_date') as string | null}</span>
|
<span>
|
||||||
|
{row.getValue('formatted_end_date') as string | null}
|
||||||
|
</span>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -57,12 +64,16 @@ export function createAcademicTermColumns(
|
|||||||
headerClassName: 'w-[100px] text-center',
|
headerClassName: 'w-[100px] text-center',
|
||||||
},
|
},
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
const isActive = row.getValue('is_active') as boolean;
|
const academicTerm = row.original;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<Badge variant={isActive ? 'default' : 'secondary'}>
|
<ActiveStatusSwitch
|
||||||
{isActive ? 'Aktif' : 'Nonaktif'}
|
isActive={academicTerm.is_active}
|
||||||
</Badge>
|
onChange={(isActive) =>
|
||||||
|
handleStatusChange(academicTerm, isActive)
|
||||||
|
}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@ -21,6 +21,7 @@ import {
|
|||||||
destroy,
|
destroy,
|
||||||
store,
|
store,
|
||||||
update,
|
update,
|
||||||
|
update_status,
|
||||||
} from '@/routes/admin/master/academic-terms';
|
} from '@/routes/admin/master/academic-terms';
|
||||||
import type { AcademicTerm } from '@/types/academic-term';
|
import type { AcademicTerm } from '@/types/academic-term';
|
||||||
import { Semester, SemesterLabels } from '@/types/academic-term';
|
import { Semester, SemesterLabels } from '@/types/academic-term';
|
||||||
@ -98,9 +99,18 @@ export default function AcademicTermIndex({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleStatusChange(academicTerm: AcademicTerm, isActive: boolean) {
|
||||||
|
router.patch(
|
||||||
|
update_status.url(academicTerm.id),
|
||||||
|
{ is_active: isActive },
|
||||||
|
{ preserveScroll: true },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const columns = createAcademicTermColumns({
|
const columns = createAcademicTermColumns({
|
||||||
handleEdit: (academicTerm) => setEditing(academicTerm),
|
handleEdit: (academicTerm) => setEditing(academicTerm),
|
||||||
handleDeleteClick: (academicTerm) => setDeleting(academicTerm),
|
handleDeleteClick: (academicTerm) => setDeleting(academicTerm),
|
||||||
|
handleStatusChange,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import type { ColumnDef } from '@tanstack/react-table';
|
import type { ColumnDef } from '@tanstack/react-table';
|
||||||
import { Key, Pencil, Trash2 } from 'lucide-react';
|
import { Key, Pencil, Trash2 } from 'lucide-react';
|
||||||
|
import { ActiveStatusSwitch } from '@/components/active-status-switch';
|
||||||
import { GenderBadge } from '@/components/gender-badge';
|
import { GenderBadge } from '@/components/gender-badge';
|
||||||
import { RowActions } from '@/components/row-actions';
|
import { RowActions } from '@/components/row-actions';
|
||||||
import { UserActiveSwitch } from '@/components/user-active-switch';
|
|
||||||
|
|
||||||
export type Administrator = {
|
export type Administrator = {
|
||||||
id: number;
|
id: number;
|
||||||
@ -69,7 +69,7 @@ export function createAdministratorColumns(
|
|||||||
accessorKey: 'is_active',
|
accessorKey: 'is_active',
|
||||||
header: () => <span>Status Akun</span>,
|
header: () => <span>Status Akun</span>,
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<UserActiveSwitch
|
<ActiveStatusSwitch
|
||||||
isActive={row.original.is_active}
|
isActive={row.original.is_active}
|
||||||
onChange={(isActive) =>
|
onChange={(isActive) =>
|
||||||
handleUserStatusChange(row.original, isActive)
|
handleUserStatusChange(row.original, isActive)
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import type { ColumnDef } from '@tanstack/react-table';
|
import type { ColumnDef } from '@tanstack/react-table';
|
||||||
import { Key, Pencil, Trash2 } from 'lucide-react';
|
import { Key, Pencil, Trash2 } from 'lucide-react';
|
||||||
|
import { ActiveStatusSwitch } from '@/components/active-status-switch';
|
||||||
import { GenderBadge } from '@/components/gender-badge';
|
import { GenderBadge } from '@/components/gender-badge';
|
||||||
import { RowActions } from '@/components/row-actions';
|
import { RowActions } from '@/components/row-actions';
|
||||||
import { UserActiveSwitch } from '@/components/user-active-switch';
|
|
||||||
|
|
||||||
export type Lecturer = {
|
export type Lecturer = {
|
||||||
id: number;
|
id: number;
|
||||||
@ -79,7 +79,7 @@ export function createLecturerColumns(
|
|||||||
accessorKey: 'is_active',
|
accessorKey: 'is_active',
|
||||||
header: () => <span>Status Akun</span>,
|
header: () => <span>Status Akun</span>,
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<UserActiveSwitch
|
<ActiveStatusSwitch
|
||||||
isActive={row.original.is_active}
|
isActive={row.original.is_active}
|
||||||
onChange={(isActive) =>
|
onChange={(isActive) =>
|
||||||
handleUserStatusChange(row.original, isActive)
|
handleUserStatusChange(row.original, isActive)
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import type { ColumnDef } from '@tanstack/react-table';
|
import type { ColumnDef } from '@tanstack/react-table';
|
||||||
import { Key, Pencil, Trash2 } from 'lucide-react';
|
import { Key, Pencil, Trash2 } from 'lucide-react';
|
||||||
|
import { ActiveStatusSwitch } from '@/components/active-status-switch';
|
||||||
import { GenderBadge } from '@/components/gender-badge';
|
import { GenderBadge } from '@/components/gender-badge';
|
||||||
import { RowActions } from '@/components/row-actions';
|
import { RowActions } from '@/components/row-actions';
|
||||||
import { StudentStatusBadge } from '@/components/student-status-badge';
|
import { StudentStatusBadge } from '@/components/student-status-badge';
|
||||||
import { UserActiveSwitch } from '@/components/user-active-switch';
|
|
||||||
|
|
||||||
export type Student = {
|
export type Student = {
|
||||||
id: number;
|
id: number;
|
||||||
@ -106,7 +106,7 @@ export function createStudentColumns(
|
|||||||
accessorKey: 'is_active',
|
accessorKey: 'is_active',
|
||||||
header: () => <span>Status Akun</span>,
|
header: () => <span>Status Akun</span>,
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<UserActiveSwitch
|
<ActiveStatusSwitch
|
||||||
isActive={row.original.is_active}
|
isActive={row.original.is_active}
|
||||||
onChange={(isActive) =>
|
onChange={(isActive) =>
|
||||||
handleUserStatusChange(row.original, isActive)
|
handleUserStatusChange(row.original, isActive)
|
||||||
|
|||||||
@ -27,6 +27,7 @@
|
|||||||
Route::middleware(['auth', 'verified'])->group(function () {
|
Route::middleware(['auth', 'verified'])->group(function () {
|
||||||
Route::prefix('admin/master')->name('admin.master.')->group(function () {
|
Route::prefix('admin/master')->name('admin.master.')->group(function () {
|
||||||
Route::resource('academic-terms', AcademicTermController::class)->except(['create', 'edit', 'show']);
|
Route::resource('academic-terms', AcademicTermController::class)->except(['create', 'edit', 'show']);
|
||||||
|
Route::patch('academic-terms/{academic_term}/status', [AcademicTermController::class, 'updateStatus'])->name('academic-terms.update_status');
|
||||||
Route::resource('departments', DepartmentController::class)->except(['create', 'edit', 'show']);
|
Route::resource('departments', DepartmentController::class)->except(['create', 'edit', 'show']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user