feat: implement user status management with active/inactive toggle
Some checks failed
tests / ci (pull_request) Has been cancelled
Some checks failed
tests / ci (pull_request) Has been cancelled
This commit is contained in:
parent
249a3c86b4
commit
9c03876a71
32
app/Actions/Fortify/AuthenticateUser.php
Normal file
32
app/Actions/Fortify/AuthenticateUser.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Fortify;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
use Laravel\Fortify\Fortify;
|
||||||
|
|
||||||
|
class AuthenticateUser
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Resolve the user attempting to log in, rejecting inactive accounts.
|
||||||
|
*/
|
||||||
|
public function __invoke(Request $request): ?User
|
||||||
|
{
|
||||||
|
$user = User::where(Fortify::username(), $request->input(Fortify::username()))->first();
|
||||||
|
|
||||||
|
if (! $user || ! Hash::check($request->password, $user->password)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $user->is_active) {
|
||||||
|
throw ValidationException::withMessages([
|
||||||
|
Fortify::username() => 'Akun Anda tidak aktif. Silakan hubungi administrator.',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
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;
|
||||||
@ -77,4 +78,11 @@ 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
|
||||||
|
{
|
||||||
|
$this->service->updateUserStatus($user, $request->boolean('is_active'));
|
||||||
|
|
||||||
|
return Inertia::flash('toast', ['type' => 'success', 'message' => 'Status akun berhasil diperbarui.'])->back();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
use App\Exports\LecturersExport;
|
use App\Exports\LecturersExport;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
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;
|
||||||
@ -84,6 +85,13 @@ 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
|
||||||
|
{
|
||||||
|
$this->service->updateUserStatus($user, $request->boolean('is_active'));
|
||||||
|
|
||||||
|
return Inertia::flash('toast', ['type' => 'success', 'message' => 'Status akun berhasil diperbarui.'])->back();
|
||||||
|
}
|
||||||
|
|
||||||
public function export(PaginatedRequest $request): BinaryFileResponse
|
public function export(PaginatedRequest $request): BinaryFileResponse
|
||||||
{
|
{
|
||||||
return Excel::download(new LecturersExport(
|
return Excel::download(new LecturersExport(
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
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;
|
||||||
@ -99,6 +100,13 @@ 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
|
||||||
|
{
|
||||||
|
$this->service->updateUserStatus($user, $request->boolean('is_active'));
|
||||||
|
|
||||||
|
return Inertia::flash('toast', ['type' => 'success', 'message' => 'Status akun berhasil diperbarui.'])->back();
|
||||||
|
}
|
||||||
|
|
||||||
public function export(PaginatedRequest $request): BinaryFileResponse
|
public function export(PaginatedRequest $request): BinaryFileResponse
|
||||||
{
|
{
|
||||||
return Excel::download(new StudentsExport(
|
return Excel::download(new StudentsExport(
|
||||||
|
|||||||
20
app/Http/Requests/Admin/Users/UpdateUserStatusRequest.php
Normal file
20
app/Http/Requests/Admin/Users/UpdateUserStatusRequest.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Admin\Users;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class UpdateUserStatusRequest extends FormRequest
|
||||||
|
{
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'is_active' => ['required', 'boolean'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Providers;
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use App\Actions\Fortify\AuthenticateUser;
|
||||||
use App\Actions\Fortify\ResetUserPassword;
|
use App\Actions\Fortify\ResetUserPassword;
|
||||||
use Illuminate\Cache\RateLimiting\Limit;
|
use Illuminate\Cache\RateLimiting\Limit;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
@ -30,6 +31,7 @@ public function boot(): void
|
|||||||
private function configureActions(): void
|
private function configureActions(): void
|
||||||
{
|
{
|
||||||
Fortify::resetUserPasswordsUsing(ResetUserPassword::class);
|
Fortify::resetUserPasswordsUsing(ResetUserPassword::class);
|
||||||
|
Fortify::authenticateUsing(new AuthenticateUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function configureViews(): void
|
private function configureViews(): void
|
||||||
|
|||||||
@ -84,4 +84,9 @@ public function resetPassword(User $user): void
|
|||||||
'password' => Hash::make(config('app.default_password')),
|
'password' => Hash::make(config('app.default_password')),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function updateUserStatus(User $user, bool $isActive): void
|
||||||
|
{
|
||||||
|
$user->update(['is_active' => $isActive]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -115,4 +115,9 @@ public function resetPassword(User $user): void
|
|||||||
'password' => Hash::make(config('app.default_password')),
|
'password' => Hash::make(config('app.default_password')),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function updateUserStatus(User $user, bool $isActive): void
|
||||||
|
{
|
||||||
|
$user->update(['is_active' => $isActive]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -126,4 +126,9 @@ public function updateStatus(User $user, string $status): void
|
|||||||
{
|
{
|
||||||
$user->student()->update(['status' => $status]);
|
$user->student()->update(['status' => $status]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function updateUserStatus(User $user, bool $isActive): void
|
||||||
|
{
|
||||||
|
$user->update(['is_active' => $isActive]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
33
resources/js/components/ui/switch.tsx
Normal file
33
resources/js/components/ui/switch.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
import { Switch as SwitchPrimitive } from "radix-ui"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
function Switch({
|
||||||
|
className,
|
||||||
|
size = "default",
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof SwitchPrimitive.Root> & {
|
||||||
|
size?: "sm" | "default"
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<SwitchPrimitive.Root
|
||||||
|
data-slot="switch"
|
||||||
|
data-size={size}
|
||||||
|
className={cn(
|
||||||
|
"peer group/switch inline-flex shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-[1.15rem] data-[size=default]:w-8 data-[size=sm]:h-3.5 data-[size=sm]:w-6 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input dark:data-[state=unchecked]:bg-input/80",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<SwitchPrimitive.Thumb
|
||||||
|
data-slot="switch-thumb"
|
||||||
|
className={cn(
|
||||||
|
"pointer-events-none block rounded-full bg-background ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0 dark:data-[state=checked]:bg-primary-foreground dark:data-[state=unchecked]:bg-foreground"
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</SwitchPrimitive.Root>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Switch }
|
||||||
17
resources/js/components/user-active-switch.tsx
Normal file
17
resources/js/components/user-active-switch.tsx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { Switch } from '@/components/ui/switch';
|
||||||
|
|
||||||
|
type UserActiveSwitchProps = {
|
||||||
|
isActive: boolean;
|
||||||
|
onChange: (isActive: boolean) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function UserActiveSwitch({ isActive, onChange }: UserActiveSwitchProps) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Switch checked={isActive} onCheckedChange={onChange} />
|
||||||
|
<span className="text-sm text-muted-foreground">
|
||||||
|
{isActive ? 'Aktif' : 'Nonaktif'}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -2,11 +2,13 @@ import type { ColumnDef } from '@tanstack/react-table';
|
|||||||
import { Key, Pencil, Trash2 } from 'lucide-react';
|
import { Key, Pencil, Trash2 } from 'lucide-react';
|
||||||
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;
|
||||||
username: string;
|
username: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
is_active: boolean;
|
||||||
profile: { full_name: string; phone_number: string; gender: string } | null;
|
profile: { full_name: string; phone_number: string; gender: string } | null;
|
||||||
roles: { id: number; name: string }[];
|
roles: { id: number; name: string }[];
|
||||||
};
|
};
|
||||||
@ -15,12 +17,18 @@ type CreateColumnsParams = {
|
|||||||
handleEdit: (admin: Administrator) => void;
|
handleEdit: (admin: Administrator) => void;
|
||||||
handleDeleteClick: (admin: Administrator) => void;
|
handleDeleteClick: (admin: Administrator) => void;
|
||||||
handleResetPassword: (admin: Administrator) => void;
|
handleResetPassword: (admin: Administrator) => void;
|
||||||
|
handleUserStatusChange: (admin: Administrator, isActive: boolean) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function createAdministratorColumns(
|
export function createAdministratorColumns(
|
||||||
params: CreateColumnsParams,
|
params: CreateColumnsParams,
|
||||||
): ColumnDef<Administrator>[] {
|
): ColumnDef<Administrator>[] {
|
||||||
const { handleEdit, handleDeleteClick, handleResetPassword } = params;
|
const {
|
||||||
|
handleEdit,
|
||||||
|
handleDeleteClick,
|
||||||
|
handleResetPassword,
|
||||||
|
handleUserStatusChange,
|
||||||
|
} = params;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@ -57,6 +65,18 @@ export function createAdministratorColumns(
|
|||||||
<GenderBadge gender={row.original.profile?.gender} />
|
<GenderBadge gender={row.original.profile?.gender} />
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'is_active',
|
||||||
|
header: () => <span>Status Akun</span>,
|
||||||
|
cell: ({ row }) => (
|
||||||
|
<UserActiveSwitch
|
||||||
|
isActive={row.original.is_active}
|
||||||
|
onChange={(isActive) =>
|
||||||
|
handleUserStatusChange(row.original, isActive)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'actions',
|
id: 'actions',
|
||||||
header: () => <span className="block text-center">Aksi</span>,
|
header: () => <span className="block text-center">Aksi</span>,
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import {
|
|||||||
destroy,
|
destroy,
|
||||||
edit,
|
edit,
|
||||||
reset_password,
|
reset_password,
|
||||||
|
update_user_status,
|
||||||
} from '@/routes/admin/users/administrators';
|
} from '@/routes/admin/users/administrators';
|
||||||
import type { Administrator } from './columns';
|
import type { Administrator } from './columns';
|
||||||
import { createAdministratorColumns } from './columns';
|
import { createAdministratorColumns } from './columns';
|
||||||
@ -91,12 +92,21 @@ export default function AdministratorIndex({ administrators, filters }: Props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleUserStatusChange(admin: Administrator, isActive: boolean) {
|
||||||
|
router.patch(
|
||||||
|
update_user_status.url(admin.id),
|
||||||
|
{ is_active: isActive },
|
||||||
|
{ preserveScroll: true },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const columns = createAdministratorColumns({
|
const columns = createAdministratorColumns({
|
||||||
handleEdit: (admin) => {
|
handleEdit: (admin) => {
|
||||||
router.get(edit.url(admin.id));
|
router.get(edit.url(admin.id));
|
||||||
},
|
},
|
||||||
handleDeleteClick: (admin) => setDeleting(admin),
|
handleDeleteClick: (admin) => setDeleting(admin),
|
||||||
handleResetPassword: (admin) => setResetting(admin),
|
handleResetPassword: (admin) => setResetting(admin),
|
||||||
|
handleUserStatusChange,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -2,11 +2,13 @@ import type { ColumnDef } from '@tanstack/react-table';
|
|||||||
import { Key, Pencil, Trash2 } from 'lucide-react';
|
import { Key, Pencil, Trash2 } from 'lucide-react';
|
||||||
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;
|
||||||
username: string;
|
username: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
is_active: boolean;
|
||||||
profile: { full_name: string; phone_number: string; gender: string } | null;
|
profile: { full_name: string; phone_number: string; gender: string } | null;
|
||||||
lecturer: {
|
lecturer: {
|
||||||
lecturer_number: string;
|
lecturer_number: string;
|
||||||
@ -18,12 +20,18 @@ type CreateColumnsParams = {
|
|||||||
handleEdit: (lecturer: Lecturer) => void;
|
handleEdit: (lecturer: Lecturer) => void;
|
||||||
handleDeleteClick: (lecturer: Lecturer) => void;
|
handleDeleteClick: (lecturer: Lecturer) => void;
|
||||||
handleResetPassword: (lecturer: Lecturer) => void;
|
handleResetPassword: (lecturer: Lecturer) => void;
|
||||||
|
handleUserStatusChange: (lecturer: Lecturer, isActive: boolean) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function createLecturerColumns(
|
export function createLecturerColumns(
|
||||||
params: CreateColumnsParams,
|
params: CreateColumnsParams,
|
||||||
): ColumnDef<Lecturer>[] {
|
): ColumnDef<Lecturer>[] {
|
||||||
const { handleEdit, handleDeleteClick, handleResetPassword } = params;
|
const {
|
||||||
|
handleEdit,
|
||||||
|
handleDeleteClick,
|
||||||
|
handleResetPassword,
|
||||||
|
handleUserStatusChange,
|
||||||
|
} = params;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@ -67,6 +75,18 @@ export function createLecturerColumns(
|
|||||||
<GenderBadge gender={row.original.profile?.gender} />
|
<GenderBadge gender={row.original.profile?.gender} />
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'is_active',
|
||||||
|
header: () => <span>Status Akun</span>,
|
||||||
|
cell: ({ row }) => (
|
||||||
|
<UserActiveSwitch
|
||||||
|
isActive={row.original.is_active}
|
||||||
|
onChange={(isActive) =>
|
||||||
|
handleUserStatusChange(row.original, isActive)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'actions',
|
id: 'actions',
|
||||||
header: () => <span className="block text-center">Aksi</span>,
|
header: () => <span className="block text-center">Aksi</span>,
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import {
|
|||||||
edit,
|
edit,
|
||||||
destroy,
|
destroy,
|
||||||
reset_password,
|
reset_password,
|
||||||
|
update_user_status,
|
||||||
exportMethod as exportLecturers,
|
exportMethod as exportLecturers,
|
||||||
} from '@/routes/admin/users/lecturers';
|
} from '@/routes/admin/users/lecturers';
|
||||||
import type { Lecturer } from './columns';
|
import type { Lecturer } from './columns';
|
||||||
@ -108,12 +109,21 @@ export default function LecturerIndex({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleUserStatusChange(lecturer: Lecturer, isActive: boolean) {
|
||||||
|
router.patch(
|
||||||
|
update_user_status.url(lecturer.id),
|
||||||
|
{ is_active: isActive },
|
||||||
|
{ preserveScroll: true },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const columns = createLecturerColumns({
|
const columns = createLecturerColumns({
|
||||||
handleEdit: (lecturer) => {
|
handleEdit: (lecturer) => {
|
||||||
router.get(edit.url(lecturer.id));
|
router.get(edit.url(lecturer.id));
|
||||||
},
|
},
|
||||||
handleDeleteClick: (lecturer) => setDeleting(lecturer),
|
handleDeleteClick: (lecturer) => setDeleting(lecturer),
|
||||||
handleResetPassword: (lecturer) => setResetting(lecturer),
|
handleResetPassword: (lecturer) => setResetting(lecturer),
|
||||||
|
handleUserStatusChange,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -3,11 +3,13 @@ import { Key, Pencil, Trash2 } from 'lucide-react';
|
|||||||
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;
|
||||||
username: string;
|
username: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
is_active: boolean;
|
||||||
profile: { full_name: string; phone_number: string; gender: string } | null;
|
profile: { full_name: string; phone_number: string; gender: string } | null;
|
||||||
student: {
|
student: {
|
||||||
student_number: string;
|
student_number: string;
|
||||||
@ -24,6 +26,7 @@ type CreateColumnsParams = {
|
|||||||
handleDeleteClick: (student: Student) => void;
|
handleDeleteClick: (student: Student) => void;
|
||||||
handleResetPassword: (student: Student) => void;
|
handleResetPassword: (student: Student) => void;
|
||||||
handleStatusChange: (student: Student, status: string) => void;
|
handleStatusChange: (student: Student, status: string) => void;
|
||||||
|
handleUserStatusChange: (student: Student, isActive: boolean) => void;
|
||||||
statuses: StatusOption[];
|
statuses: StatusOption[];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -35,6 +38,7 @@ export function createStudentColumns(
|
|||||||
handleDeleteClick,
|
handleDeleteClick,
|
||||||
handleResetPassword,
|
handleResetPassword,
|
||||||
handleStatusChange,
|
handleStatusChange,
|
||||||
|
handleUserStatusChange,
|
||||||
statuses,
|
statuses,
|
||||||
} = params;
|
} = params;
|
||||||
|
|
||||||
@ -98,6 +102,18 @@ export function createStudentColumns(
|
|||||||
<GenderBadge gender={row.original.profile?.gender} />
|
<GenderBadge gender={row.original.profile?.gender} />
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'is_active',
|
||||||
|
header: () => <span>Status Akun</span>,
|
||||||
|
cell: ({ row }) => (
|
||||||
|
<UserActiveSwitch
|
||||||
|
isActive={row.original.is_active}
|
||||||
|
onChange={(isActive) =>
|
||||||
|
handleUserStatusChange(row.original, isActive)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'actions',
|
id: 'actions',
|
||||||
header: () => <span className="block text-center">Aksi</span>,
|
header: () => <span className="block text-center">Aksi</span>,
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import {
|
|||||||
edit,
|
edit,
|
||||||
reset_password,
|
reset_password,
|
||||||
update_status,
|
update_status,
|
||||||
|
update_user_status,
|
||||||
exportMethod as exportStudents,
|
exportMethod as exportStudents,
|
||||||
index as studentsIndex,
|
index as studentsIndex,
|
||||||
} from '@/routes/admin/users/students';
|
} from '@/routes/admin/users/students';
|
||||||
@ -127,6 +128,14 @@ export default function StudentIndex({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleUserStatusChange(student: Student, isActive: boolean) {
|
||||||
|
router.patch(
|
||||||
|
update_user_status.url(student.id),
|
||||||
|
{ is_active: isActive },
|
||||||
|
{ preserveScroll: true },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const columns = createStudentColumns({
|
const columns = createStudentColumns({
|
||||||
handleEdit: (student) => {
|
handleEdit: (student) => {
|
||||||
router.get(edit.url(student.id));
|
router.get(edit.url(student.id));
|
||||||
@ -134,6 +143,7 @@ export default function StudentIndex({
|
|||||||
handleDeleteClick: (student) => setDeleting(student),
|
handleDeleteClick: (student) => setDeleting(student),
|
||||||
handleResetPassword: (student) => setResetting(student),
|
handleResetPassword: (student) => setResetting(student),
|
||||||
handleStatusChange,
|
handleStatusChange,
|
||||||
|
handleUserStatusChange,
|
||||||
statuses,
|
statuses,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -119,14 +119,17 @@
|
|||||||
Route::prefix('admin/users')->name('admin.users.')->group(function () {
|
Route::prefix('admin/users')->name('admin.users.')->group(function () {
|
||||||
Route::resource('lecturers', LecturerController::class)->except(['show'])->parameters(['lecturers' => 'user']);
|
Route::resource('lecturers', LecturerController::class)->except(['show'])->parameters(['lecturers' => 'user']);
|
||||||
Route::patch('lecturers/{user}/reset-password', [LecturerController::class, 'resetPassword'])->name('lecturers.reset_password');
|
Route::patch('lecturers/{user}/reset-password', [LecturerController::class, 'resetPassword'])->name('lecturers.reset_password');
|
||||||
|
Route::patch('lecturers/{user}/user-status', [LecturerController::class, 'updateUserStatus'])->name('lecturers.update_user_status');
|
||||||
Route::get('lecturers/export', [LecturerController::class, 'export'])->name('lecturers.export');
|
Route::get('lecturers/export', [LecturerController::class, 'export'])->name('lecturers.export');
|
||||||
|
|
||||||
Route::resource('students', StudentController::class)->except(['show'])->parameters(['students' => 'user']);
|
Route::resource('students', StudentController::class)->except(['show'])->parameters(['students' => 'user']);
|
||||||
Route::patch('students/{user}/reset-password', [StudentController::class, 'resetPassword'])->name('students.reset_password');
|
Route::patch('students/{user}/reset-password', [StudentController::class, 'resetPassword'])->name('students.reset_password');
|
||||||
Route::patch('students/{user}/status', [StudentController::class, 'updateStatus'])->name('students.update_status');
|
Route::patch('students/{user}/status', [StudentController::class, 'updateStatus'])->name('students.update_status');
|
||||||
|
Route::patch('students/{user}/user-status', [StudentController::class, 'updateUserStatus'])->name('students.update_user_status');
|
||||||
Route::get('students/export', [StudentController::class, 'export'])->name('students.export');
|
Route::get('students/export', [StudentController::class, 'export'])->name('students.export');
|
||||||
|
|
||||||
Route::resource('administrators', AdministratorController::class)->except(['show'])->parameters(['administrators' => 'user']);
|
Route::resource('administrators', AdministratorController::class)->except(['show'])->parameters(['administrators' => 'user']);
|
||||||
Route::patch('administrators/{user}/reset-password', [AdministratorController::class, 'resetPassword'])->name('administrators.reset_password');
|
Route::patch('administrators/{user}/reset-password', [AdministratorController::class, 'resetPassword'])->name('administrators.reset_password');
|
||||||
|
Route::patch('administrators/{user}/user-status', [AdministratorController::class, 'updateUserStatus'])->name('administrators.update_user_status');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user