f84c21f829
This commit introduces a new `clearable` prop to the `Select` component, allowing users to easily reset its value. When the `clearable` prop is set to true, a clear button (an 'X' icon) is displayed when an option is selected. Clicking this button resets the select input to its initial placeholder state and triggers an optional `onClear` callback. To support this, the component's internal state management was refactored to control the input's value. Additionally, the `AdminListFilters` component has been updated to: - Utilize the new clearable select for the status filter. - Consolidate multiple search fields (email, username, full_name) into a single generic "search" input. - Add explicit "Reset" and "Apply" buttons for better filter management.
113 lines
2.6 KiB
TypeScript
113 lines
2.6 KiB
TypeScript
import { ILabelValue } from "@/types/shared";
|
|
import * as moment from "moment";
|
|
import { z } from "zod";
|
|
export const unixToDate = ({
|
|
hasTime = false,
|
|
unix,
|
|
}: {
|
|
unix: number;
|
|
hasTime?: boolean;
|
|
}) => {
|
|
return moment.unix(unix).format(`YYYY/MM/DD ${hasTime ? "HH:MM" : ""}`);
|
|
};
|
|
export const msToDate = (ms: number) => {
|
|
return moment.default(ms).format("YYYY/MM/DD");
|
|
};
|
|
|
|
export const isoStringToDate = ({
|
|
hasTime = false,
|
|
isoString,
|
|
}: {
|
|
isoString: string;
|
|
hasTime: boolean;
|
|
}): string => {
|
|
return moment
|
|
.default(isoString)
|
|
.format(`YYYY/MM/DD ${hasTime ? "HH:MM" : ""}`);
|
|
};
|
|
|
|
export const getStatusColor = <T>(status: T) => {
|
|
switch (status) {
|
|
case "active":
|
|
return "bg-green text-white";
|
|
case "expired":
|
|
return "bg-orange-light text-white";
|
|
case "cancelled":
|
|
return "bg-error-dark text-white";
|
|
case "awarded":
|
|
return "bg-blue-light-3";
|
|
case "draft":
|
|
return "bg-gray-3";
|
|
}
|
|
};
|
|
export const formatPhoneNumber = (input?: string) => {
|
|
if (!input) return "";
|
|
|
|
let cleaned = input.replace(/[^\d+]/g, "");
|
|
|
|
const hasPlus = cleaned.startsWith("+");
|
|
if (hasPlus) {
|
|
cleaned = cleaned.slice(1);
|
|
}
|
|
|
|
const groups = [];
|
|
let i = 0;
|
|
while (i < cleaned.length) {
|
|
const size = i === 0 ? 3 : 4;
|
|
groups.push(cleaned.slice(i, i + size));
|
|
i += size;
|
|
}
|
|
|
|
return (hasPlus ? "+" : "") + groups.join(" ");
|
|
};
|
|
export const capitalize = (text: string) => {
|
|
return text
|
|
.split(" ")
|
|
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
.join(" ")
|
|
.trim();
|
|
};
|
|
export const getEnumAsArray = <T extends object>(target: T): ILabelValue[] => {
|
|
return Object.entries(target).map(([key, value]) => ({
|
|
label: capitalize(key.split("_").join(" ")),
|
|
value,
|
|
}));
|
|
};
|
|
export const truncateString = (
|
|
str: string,
|
|
startLength: number = 10,
|
|
endLength: number = 10,
|
|
): string => {
|
|
if (str.length <= startLength + endLength) {
|
|
return str;
|
|
}
|
|
return str.slice(0, startLength) + "..." + str.slice(-endLength);
|
|
};
|
|
|
|
export function parseWithSchema<T>(
|
|
schema: z.ZodSchema<T>,
|
|
data: unknown,
|
|
errorContext: string,
|
|
): T {
|
|
const parsedData = schema.safeParse(data);
|
|
|
|
if (parsedData.success) {
|
|
return parsedData.data;
|
|
} else {
|
|
console.error(`ERROR caught in ${errorContext}`);
|
|
throw new Error(`ERROR caught in ${errorContext}`);
|
|
}
|
|
}
|
|
|
|
export const deleteEmptyKeys = (obj: Record<string, any>) => {
|
|
const newObj = { ...obj };
|
|
for (const key in newObj) {
|
|
if (Object.prototype.hasOwnProperty.call(newObj, key)) {
|
|
if (!newObj[key]) {
|
|
delete newObj[key];
|
|
}
|
|
}
|
|
}
|
|
return newObj;
|
|
};
|