chore: phase 1 lint/type fixes — commit all changes

This commit is contained in:
m7amedez5511
2026-07-02 20:07:38 +03:00
parent d225291b70
commit 25f3468d74
37 changed files with 162 additions and 176 deletions

View File

@@ -15,9 +15,9 @@ export default function Navbar() {
return (
<nav dir="rtl" className="w-full border-b border-slate-200 bg-white text-slate-900 shadow-sm">
<div className="mx-auto flex h-14 max-w-7xl items-center gap-4 px-6 lg:px-8">
<a href="/" className="flex items-center gap-3 text-right">
<Link href="/" className="flex items-center gap-3 text-right">
<Logo />
</a>
</Link>
<div className="hidden flex-1 items-center justify-center gap-6 md:flex">
{navLinks.map((link) => (

View File

@@ -1,23 +1,6 @@
// app/dashboard/clients/[clientId]/addresses/page.tsx
//
// ── Refactor notes ──────────────────────────────────────────────────────────
// • Address cards are no longer clickable / navigable. Removed the `onView`
// prop, the card's onClick handler, and the pointer cursor + hover styles
// that implied the card itself was a link.
// • Each AddressCard now renders full address details inline (street, city,
// state, district, building/unit/additional no., zip code, country, and
// contact person), instead of a 3-line summary that deferred to the
// AddressDetail page.
// • Removed all routing to the address detail route.
// • Deleted as part of this refactor (no longer referenced anywhere):
// - app/dashboard/clients/[clientId]/addresses/[addressId]/page.tsx
// - app/dashboard/clients/[clientId]/addresses/[addressesId]/page.tsx
// - src/Components/Client_Adress/AddressDetails.tsx
// ─────────────────────────────────────────────────────────────────────────
"use client";
import { useEffect, useState } from "react";
import { useCallback, useEffect, useState } from "react";
import { useParams, useRouter } from "next/navigation";
import { Alert, Toast } from "@/src/Components/UI";
@@ -336,16 +319,22 @@ export default function ClientAddressesPage() {
const [client, setClient] = useState<Client | null>(null);
const [clientLoading, setClientLoading] = useState(true);
useEffect(() => {
const loadClient = useCallback(() => {
if (!clientId) return;
queueMicrotask(() => {
setClientLoading(true);
clientService
.getById(clientId, getStoredToken())
.then((res) => setClient(res.data))
.catch(() => router.replace("/dashboard/clients"))
.finally(() => setClientLoading(false));
});
}, [clientId, router]);
useEffect(() => {
loadClient();
}, [loadClient]);
// ── Address hook ─────────────────────────────────────────────────────────
const {
addresses,
@@ -356,7 +345,6 @@ export default function ClientAddressesPage() {
createAddress,
updateAddress,
deleteAddress,
reload,
} = useClientAddresses(clientId ?? "");
// ── Modal state ──────────────────────────────────────────────────────────
@@ -386,7 +374,6 @@ export default function ClientAddressesPage() {
// ── Client edit handler ──────────────────────────────────────────────────
const handleClientEditSubmit = async (
data: ClientFormData,
_isNew: boolean
): Promise<boolean> => {
if (!client) return false;
try {

View File

@@ -6,11 +6,11 @@ import { Spinner } from "@/src/Components/UI";
import { DriverFormModal } from "@/src/Components/Driver/DriverFormModal";
import { DriverDeleteModal } from "@/src/Components/Driver/DriverDeleteModal";
import { DriverReportPanel } from "@/src/Components/Driver_Report/driverReport";
import { driverService } from "@/services";
import { getStoredToken } from "@/lib/auth";
import type { Driver, CreateDriverPayload, UpdateDriverPayload } from "@/src/types/driver";
import { DRIVER_STATUS_MAP, DRIVER_CARD_TYPE_MAP, NATIONAL_ID_TYPE_MAP } from "@/src/types/driver";
import { PhotoCard } from "@/src/Components/Driver/DriverPhotos";
import { driverService } from "@/src/services";
import { getStoredToken } from "@/src/lib/auth";
// ── Helpers ───────────────────────────────────────────────────────────────────
@@ -88,9 +88,7 @@ export default function DriverDetailPage() {
const [avatarError, setAvatarError] = useState(false);
// Reset avatar error when photo changes after an update
useEffect(() => {
console.log(driver?.photoUrl);
setAvatarError(false);
queueMicrotask(() => setAvatarError(false));
}, [driver?.photoUrl]);
// Toast shown after edit/delete actions on this page
const [toast, setToast] = useState<{ type: "success" | "error"; message: string } | null>(null);
@@ -120,11 +118,11 @@ export default function DriverDetailPage() {
}
}, [driverId]);
useEffect(() => { loadDriver(); }, [loadDriver]);
useEffect(() => { queueMicrotask(loadDriver); }, [loadDriver]);
// ── Edit submit ───────────────────────────────────────────────────────────
const handleEditSubmit = useCallback(
async (payload: CreateDriverPayload | UpdateDriverPayload, _isNew: boolean): Promise<boolean> => {
async (payload: CreateDriverPayload | UpdateDriverPayload): Promise<boolean> => {
if (!driver) return false;
try {
const token = getStoredToken();

View File

@@ -65,7 +65,7 @@ export default function DriversPage() {
drivers, loading, error, total, pages, page,
search, setPage, handleSearch, clearError,
createDriver, updateDriver, deleteDriver,
notification, reload,
notification,
} = useDrivers();
// ── Panel / modal state ───────────────────────────────────────────────────

View File

@@ -68,7 +68,7 @@ export default function OrderComponent() {
const {
orders, loading, error, total, pages, page,
search, statusFilter, setPage, handleSearch, handleStatusFilter, clearError,
createOrder, updateOrder, updateStatus, deleteOrder,
createOrder, updateOrder, deleteOrder,
notification, reload,
} = useOrders();

View File

@@ -221,14 +221,13 @@ export default function TripDetailPage() {
}, [tripId]);
useEffect(() => {
loadTrip();
queueMicrotask(loadTrip);
}, [loadTrip]);
// ── Edit submit ───────────────────────────────────────────────────────────
const handleEditSubmit = useCallback(
async (
payload: CreateTripPayload | UpdateTripPayload,
_isNew: boolean,
): Promise<boolean> => {
if (!trip) return false;
try {

View File

@@ -141,8 +141,7 @@ function ArchivedTripsModal({ onClose }: { onClose: () => void }) {
</div>
<div style={{ padding: "1.5rem" }}>
// Was pointing at the normal trip page — send it to the archived
route instead
{/* Was pointing at the normal trip page — send it to the archived route instead */}
<ArchivedTripList
onView={(trip) =>
router.push(`/dashboard/trips/archived/${trip.id}`)

View File

@@ -2,7 +2,6 @@
import Link from "next/link";
import { useState } from "react";
import { useRouter } from "next/navigation";
import { loginUser } from "@/src/lib/auth";
import Logo from "@/src/utils/logo";
import { Button } from "@/src/Components/UI";
@@ -10,7 +9,6 @@ import { Input } from "@/src/Components/UI";
import { Alert } from "@/src/Components/UI";
export default function LoginPage() {
const router = useRouter();
const [identity, setIdentity] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState<string | null>(null);

1
dummy.txt Normal file
View File

@@ -0,0 +1 @@
dummy

1
dummy2.txt Normal file
View File

@@ -0,0 +1 @@
dummy

View File

@@ -12,7 +12,6 @@ import {
type UpdateClientFormValues,
} from "@/src/validations/client.validator";
import type { Client } from "@/src/types/client";
import { Schema } from "yup";
// ── Styles ─────────────────────────────────────────────────────────────────
const S = {
@@ -71,7 +70,7 @@ export function ClientFormModal({ editClient, onClose, onSubmit }: ClientFormMod
setError,
formState: { errors, isSubmitting },
} = useForm<CreateClientFormValues | UpdateClientFormValues>({
resolver: yupResolver(Schema) as never, // FIX 1 applied here
resolver: yupResolver(schema) as never,
defaultValues: {
name: editClient?.name ?? "",
email: editClient?.email ?? "",

View File

@@ -38,37 +38,6 @@ function AddressBadge({ count, onClick }: { count: number; onClick: () => void }
);
}
// ── Status badge ───────────────────────────────────────────────────────────
function StatusBadge({ active }: { active?: boolean }) {
const isActive = active !== false;
return (
<span
style={{
display: "inline-flex",
alignItems: "center",
gap: 5,
borderRadius: "var(--radius-full)",
border: isActive ? "1px solid #BBF7D0" : "1px solid #FECACA",
background: isActive ? "#DCFCE7" : "#FEF2F2",
padding: "0.2rem 0.625rem",
fontSize: 11,
fontWeight: 600,
color: isActive ? "#166534" : "#991B1B",
}}
>
<span
style={{
width: 6,
height: 6,
borderRadius: "50%",
background: isActive ? "#16A34A" : "#DC2626",
}}
/>
{isActive ? "نشط" : "غير نشط"}
</span>
);
}
// ── Icon button ────────────────────────────────────────────────────────────
function IconBtn({
onClick,

View File

@@ -106,9 +106,17 @@ export function AddressFormModal({ editAddress, onClose, onSubmit }: AddressForm
},
});
const detailsErr = (errors as any)?.details ?? {};
const contactErr = (errors as any)?.contactPerson ?? {};
const locationErr = (errors as any)?.location ?? {};
type AddressErrors = {
details?: Record<string, unknown>;
contactPerson?: Record<string, unknown>;
location?: Record<string, unknown>;
};
const {
details: detailsErr = {},
contactPerson: contactErr = {},
location: locationErr = {},
} = errors as AddressErrors;
useEffect(() => {
const handler = (e: KeyboardEvent) => { if (e.key === "Escape") onClose(); };

View File

@@ -97,7 +97,7 @@ function PhotoCard({ url, label }: { url?: string | null; label: string }) {
const [imgError, setImgError] = useState(false);
useEffect(() => {
setImgError(false);
queueMicrotask(() => setImgError(false));
}, [url]);
return (
@@ -196,7 +196,7 @@ export function DriverDetailPanel({
}
}, [driverId]);
useEffect(() => { loadDriver(); }, [loadDriver]);
useEffect(() => { queueMicrotask(loadDriver); }, [loadDriver]);
useEffect(() => {
const h = (e: KeyboardEvent) => { if (e.key === "Escape") onClose(); };

View File

@@ -16,6 +16,7 @@ import type {
DriverStatus,
} from "@/src/types/driver";
import type { Branch } from "@/src/types/branch";
import { FileInput } from "@/src/Components/Driver/DriverFormModalHelper";
// ── Shared input style ───────────────────────────────────────────────────────
@@ -97,7 +98,7 @@ export function DriverFormModal({
const [branches, setBranches] = useState<Branch[]>(branchesProp);
useEffect(() => {
if (branchesProp.length > 0) {
setBranches(branchesProp);
queueMicrotask(() => setBranches(branchesProp));
return;
}
const token = getStoredToken();
@@ -108,8 +109,7 @@ export function DriverFormModal({
setBranches(list);
})
.catch(() => { /* silently ignore */ });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
}, [branchesProp]);
// ── Form state ────────────────────────────────────────────────────────────
const [name, setName] = useState(editDriver?.name ?? "");
@@ -172,7 +172,7 @@ export function DriverFormModal({
setErrors((p) => ({ ...p, [field]: undefined }));
// ── Submit with yup validation ────────────────────────────────────────────
const handleSubmit = async (e: React.FormEvent) => {
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
// Build the raw object to validate
@@ -211,7 +211,6 @@ export function DriverFormModal({
}
}
// ── Build clean payload to send to backend ────────────────────────────
const payload: Record<string, unknown> = { name, phone };
if (email) payload.email = email;
if (address) payload.address = address;
@@ -253,39 +252,6 @@ export function DriverFormModal({
}
};
// ── File input helper ──────────────────────────────────────────────────────
function FileInput({
label: lbl,
current,
onChange,
}: {
label: string;
current: File | null;
onChange: (f: File | null) => void;
}) {
return (
<label style={labelStyle}>
{lbl}
<input
type="file"
accept="image/*"
onChange={(e) => onChange(e.target.files?.[0] ?? null)}
style={{
...inputBase,
padding: "0.35rem 0.75rem",
height: "auto",
cursor: "pointer",
}}
/>
{current && (
<span style={{ fontSize: 11, color: "var(--color-text-muted)" }}>
{current.name}
</span>
)}
</label>
);
}
// ── Render ─────────────────────────────────────────────────────────────────
return (
<div

View File

@@ -0,0 +1,55 @@
import React from "react";
const inputBase: React.CSSProperties = {
width: "100%",
height: 40,
padding: "0 0.75rem",
borderRadius: "var(--radius-md)",
border: "1px solid var(--color-border)",
background: "var(--color-surface)",
fontSize: 13,
color: "var(--color-text-primary)",
outline: "none",
fontFamily: "var(--font-sans)",
};
const labelStyle: React.CSSProperties = {
display: "flex",
flexDirection: "column",
gap: 6,
fontSize: 12,
fontWeight: 600,
color: "var(--color-text-secondary)",
};
export function FileInput({
label,
current,
onChange,
}: {
label: string;
current: File | null;
onChange: (f: File | null) => void;
}) {
return (
<label style={labelStyle}>
{label}
<input
type="file"
accept="image/*"
onChange={(e) => onChange(e.target.files?.[0] ?? null)}
style={{
...inputBase,
padding: "0.35rem 0.75rem",
height: "auto",
cursor: "pointer",
}}
/>
{current && (
<span style={{ fontSize: 11, color: "var(--color-text-muted)" }}>
{current.name}
</span>
)}
</label>
);
}

View File

@@ -11,7 +11,7 @@ export function PhotoCard({
// Reset error state when url changes so updated images get a fresh load attempt
useEffect(() => {
setImgError(false);
queueMicrotask(() => setImgError(false));
}, [url]);
return (

View File

@@ -162,7 +162,7 @@ export function OrderDetailPanel({
}
}, [orderId]);
useEffect(() => { loadOrder(); }, [loadOrder]);
useEffect(() => { queueMicrotask(loadOrder); }, [loadOrder]);
useEffect(() => {
const h = (e: KeyboardEvent) => { if (e.key === "Escape") onClose(); };

View File

@@ -218,16 +218,16 @@ export function OrderFormModal({
// Fetch first 100 clients (enough for a practical dropdown)
const clientRes = await clientService.getAll(1, "", token);
const clientPayload = (clientRes as any).data ?? clientRes;
const clientList: Client[] = clientPayload.data ?? [];
const clientPayload = (clientRes as unknown as { data?: { data?: Client[] } }).data ?? clientRes;
const clientList: Client[] = (clientPayload as { data?: Client[] }).data ?? [];
// Fetch first 100 trips (active ones the order can be assigned to)
const tripRes = await tripService.getAll(
{ page: 1, limit: 100 },
token,
);
const tripPayload = (tripRes as any).data ?? tripRes;
const tripList: Trip[] = tripPayload.data ?? [];
const tripPayload = (tripRes as unknown as { data?: { data?: Trip[] } }).data ?? tripRes;
const tripList: Trip[] = (tripPayload as { data?: Trip[] }).data ?? [];
if (!cancelled) {
setClients(clientList);

View File

@@ -1,6 +1,6 @@
"use client";
import { Spinner, Alert, EmptyState, Badge } from "@/src/Components/UI";
import { Spinner, Alert, EmptyState } from "@/src/Components/UI";
import { useArchivedTrips } from "@/src/hooks/archive/useArchivedTrips";
import { TRIP_STATUS_MAP } from "@/src/types/trip";
import type { Trip } from "@/src/types/trip";

View File

@@ -21,7 +21,7 @@ export function Toast({ notification, onDismiss }: ToastProps) {
useEffect(() => {
if (notification) {
if (exitTimer.current) clearTimeout(exitTimer.current);
setVisible(true);
queueMicrotask(() => setVisible(true));
} else {
exitTimer.current = setTimeout(() => setVisible(false), 300);
}

View File

@@ -1,6 +1,6 @@
"use client";
import { useEffect, useRef, useState } from "react";
import { useCallback, useEffect, useRef, useState } from "react";
import * as yup from "yup";
import { Alert, Spinner } from "../UI";
import { get } from "@/src/services/api";
@@ -101,9 +101,9 @@ export function CarFormModal({
// ── Local branches (auto-fetched if prop is empty) ─────────────────────────
const [branches, setBranches] = useState<Branch[]>(branchesProp);
useEffect(() => {
const loadBranches = useCallback(() => {
if (branchesProp.length > 0) {
setBranches(branchesProp);
queueMicrotask(() => setBranches(branchesProp));
return;
}
const token = getStoredToken();
@@ -111,13 +111,16 @@ export function CarFormModal({
.then((res) => {
const list =
(res as unknown as { data: { data: Branch[] } }).data?.data ?? [];
setBranches(list);
queueMicrotask(() => setBranches(list));
})
.catch(() => {
/* silently ignore */
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
}, [branchesProp]);
useEffect(() => {
loadBranches();
}, [loadBranches]);
// ── Form state ─────────────────────────────────────────────────────────────
const [manufacturer, setManufacturer] = useState(editCar?.manufacturer ?? "");

View File

@@ -33,7 +33,7 @@ export function useCarMaintenanceList(carId: string | null) {
.finally(() => setLoading(false));
}, [carId]);
useEffect(() => { loadRecords(); }, [loadRecords]);
useEffect(() => { queueMicrotask(loadRecords); }, [loadRecords]);
// Remove a record from the list right away, instead of waiting on a refetch.
const removeRecord = useCallback((id: string) => {
@@ -51,7 +51,7 @@ export function useCarMaintenanceDetail(carId: string | null, maintenanceId: str
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const loadRecord = useCallback(() => {
if (!carId || !maintenanceId) return;
const token = getStoredToken();
setLoading(true);
@@ -63,6 +63,8 @@ export function useCarMaintenanceDetail(carId: string | null, maintenanceId: str
.finally(() => setLoading(false));
}, [carId, maintenanceId]);
useEffect(() => { queueMicrotask(loadRecord); }, [loadRecord]);
return { record, loading, error };
}

View File

@@ -19,7 +19,7 @@ export function useArchivedCars() {
const [page, setPage] = useState(1);
const [search, setSearch] = useState("");
const load = () => {
const load = useCallback(() => {
const token = getStoredToken();
setLoading(true);
setError(null);
@@ -31,9 +31,9 @@ export function useArchivedCars() {
})
.catch((err: Error) => setError(err.message))
.finally(() => setLoading(false));
};
}, []);
useEffect(() => { load(); }, []);
useEffect(() => { queueMicrotask(load); }, [load]);
const filtered = useMemo(() => {
if (!search.trim()) return allCars;

View File

@@ -33,7 +33,7 @@ export function useArchivedDrivers() {
}
}, [page, search]);
useEffect(() => { load(); }, [load]);
useEffect(() => { queueMicrotask(load); }, [load]);
/** Updates the search term and resets to page 1. */
const handleSearch = (value: string) => {

View File

@@ -30,7 +30,7 @@ export function useArchivedTrips() {
}
}, [page, search]);
useEffect(() => { load(); }, [load]);
useEffect(() => { queueMicrotask(load); }, [load]);
const handleSearch = (value: string) => {
setSearch(value);

View File

@@ -28,7 +28,7 @@ export function useArchivedUsers() {
}
}, [page, search]);
useEffect(() => { load(); }, [load]);
useEffect(() => { queueMicrotask(load); }, [load]);
const handleSearch = (value: string) => {
setSearch(value);

View File

@@ -4,7 +4,6 @@ import { useCallback, useEffect, useReducer, useState } from "react";
import { getStoredToken } from "@/src/lib/auth";
import { branchService } from "@/src/services/branch.service";
import type {
Branch,
BranchFormData,
TableAction,
TableState,

View File

@@ -41,7 +41,7 @@ export function useCars(page: number, search: string) {
.finally(() => setLoading(false));
}, [page, search]);
useEffect(() => { loadCars(); }, [loadCars]);
useEffect(() => { queueMicrotask(loadCars); }, [loadCars]);
// Optimistic removal after delete
const removeCar = useCallback((id: string) => {
@@ -61,6 +61,7 @@ export function useCarDetail(carId: string) {
const [error, setError] = useState<string | null>(null);
useEffect(() => {
queueMicrotask(() => {
const token = getStoredToken();
setLoading(true);
setError(null);
@@ -69,6 +70,7 @@ export function useCarDetail(carId: string) {
.then(res => setCar((res as unknown as { data: Car }).data))
.catch((err: Error) => setError(err.message))
.finally(() => setLoading(false));
});
}, [carId]);
return { car, loading, error };
@@ -170,7 +172,7 @@ export function useCarImages(carId: string, sortBy: "asc" | "desc") {
}
}, [carId, sortBy]);
useEffect(() => { fetchImages(); }, [fetchImages]);
useEffect(() => { queueMicrotask(fetchImages); }, [fetchImages]);
const uploadImages = useCallback(async (files: File[], stage: ImageStage) => {
setUploading(true);

View File

@@ -17,14 +17,15 @@ import { Notification } from "../types/notif";
function normalizeAddress(raw: any): ClientAddress {
function normalizeAddress(raw: unknown): ClientAddress {
const data = raw as { id?: string; _id?: string; [key: string]: unknown };
return {
...raw,
id: raw.id ?? raw._id,
...data,
id: data.id ?? data._id,
};
}
function normalizeAddresses(rawList: any[]): ClientAddress[] {
function normalizeAddresses(rawList: unknown[]): ClientAddress[] {
return rawList.map(normalizeAddress);
}
@@ -81,8 +82,8 @@ export function useClientAddresses(clientId: string) {
try {
const token = getStoredToken();
const res = await clientAddressService.getAll(clientId, token);
const payload = (res as any).data ?? res;
const rawList = Array.isArray(payload) ? payload : (payload.data ?? []);
const payload = (res as unknown as { data?: unknown }).data ?? res;
const rawList = Array.isArray(payload) ? payload : ((payload as { data?: unknown }).data ?? []);
dispatch({
type: "LOAD_OK",
addresses: normalizeAddresses(rawList),

View File

@@ -4,7 +4,6 @@ import { useCallback, useEffect, useReducer, useState } from "react";
import { getStoredToken } from "@/src/lib/auth";
import { clientService } from "@/src/services/client.service";
import type {
Client,
ClientFormData,
ClientTableAction,
ClientTableState,
@@ -62,8 +61,8 @@ export function useClients() {
const [search, setSearch] = useState("");
const [page, setPage] = useState(1);
const [notification, setNotification] = useState<Notification | null>(null);
const [roles, setRoles] = useState<[]>([]); // placeholder — extend if needed
const [branches, setBranches] = useState<[]>([]); // placeholder — extend if needed
const [roles] = useState<[]>([]); // placeholder — extend if needed
const [branches] = useState<[]>([]); // placeholder — extend if needed
/** Show a toast for 4 seconds then auto-dismiss — identical to useUsers. */
const notify = useCallback((n: Notification) => {
@@ -79,12 +78,18 @@ export function useClients() {
const res = await clientService.getAll(p, q, token);
// Normalise both pagination shapes the backend might return
const payload = (res as any).data ?? res;
const apiResponse = res as { data?: unknown };
const payload = apiResponse.data ?? res;
const response = payload as {
data?: Client[];
meta?: { total?: number; pages?: number };
pagination?: { total?: number; pages?: number };
};
dispatch({
type: "LOAD_OK",
clients: payload.data ?? [],
total: payload.meta?.total ?? payload.pagination?.total ?? 0,
pages: payload.meta?.pages ?? payload.pagination?.pages ?? 1,
clients: response.data ?? [],
total: response.meta?.total ?? response.pagination?.total ?? 0,
pages: response.meta?.pages ?? response.pagination?.pages ?? 1,
});
} catch {
dispatch({

View File

@@ -29,7 +29,7 @@ export function useDashboardSummary(): State {
const token = getStoredToken();
if (!token) {
setState({ data: null, error: "Unauthenticated", loading: false });
queueMicrotask(() => setState({ data: null, error: "Unauthenticated", loading: false }));
return;
}

View File

@@ -166,7 +166,6 @@ export function useRoles() {
async (
id: string,
data: RoleFormData,
_currentPermIds: string[],
): Promise<boolean> => {
try {
const token = getStoredToken();

View File

@@ -8,7 +8,6 @@ import type { Role } from "@/src/types/role";
import type {
TableAction,
TableState,
User,
UserFormData,
} from "@/src/types/user";
import type { ToastNotification } from "@/src/Components/UI"

View File

@@ -1,5 +1,3 @@
import { requestJson } from "@/src/lib/api";
function resolveBase() {
if (typeof window === "undefined") {
return process.env.INTERNAL_API_BASE_URL ?? "";

View File

@@ -1,8 +1,5 @@
import * as yup from "yup";
const UUID_RE =
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
export const createRoleSchema = yup.object({
name: yup
.string()