304 lines
8.3 KiB
TypeScript
304 lines
8.3 KiB
TypeScript
import { format } from "date-fns";
|
|
import { redirect } from "next/navigation";
|
|
import { DateFormatOptions, DateFormatPattern } from "../_lib/types/date-format.interface";
|
|
import { toast } from "sonner";
|
|
|
|
/**
|
|
* Redirects to a specified path with an encoded message as a query parameter.
|
|
* @param {('error' | 'success')} type - The type of message, either 'error' or 'success'.
|
|
* @param {string} path - The path to redirect to.
|
|
* @param {string} message - The message to be encoded and added as a query parameter.
|
|
* @returns {never} This function doesn't return as it triggers a redirect.
|
|
*/
|
|
export function encodedRedirect(
|
|
type: "error" | "success",
|
|
path: string,
|
|
message: string,
|
|
) {
|
|
return redirect(`${path}?${type}=${encodeURIComponent(message)}`);
|
|
}
|
|
|
|
/**
|
|
* Formats a URL by removing any trailing slashes.
|
|
* @param {string} url - The URL to format.
|
|
* @returns {string} The formatted URL.
|
|
*/
|
|
// Helper function to ensure URLs are properly formatted
|
|
export function formatUrl(url: string): string {
|
|
// If URL starts with a slash, it's already absolute
|
|
if (url.startsWith("/")) {
|
|
return url;
|
|
}
|
|
|
|
// Otherwise, ensure it's properly formatted relative to root
|
|
// Remove any potential duplicated '/dashboard' prefixes
|
|
if (url.startsWith("dashboard/")) {
|
|
return "/" + url;
|
|
}
|
|
|
|
return "/" + url;
|
|
}
|
|
|
|
/**
|
|
* Creates a FormData object from the FormData object.
|
|
* @returns {FormData} The FormData object.
|
|
*/
|
|
export function createFormData(): FormData {
|
|
const data = new FormData();
|
|
Object.entries(FormData).forEach(([key, value]) => {
|
|
if (value) {
|
|
data.append(key, value);
|
|
}
|
|
});
|
|
return data;
|
|
};
|
|
|
|
|
|
/**
|
|
* Generates a unique username based on the provided email address.
|
|
*
|
|
* The username is created by combining the local part of the email (before the '@' symbol)
|
|
* with a randomly generated alphanumeric suffix.
|
|
*
|
|
* @param email - The email address to generate the username from.
|
|
* @returns A string representing the generated username.
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* const username = generateUsername("example@gmail.com");
|
|
* console.log(username); // Output: "example.abc123" (random suffix will vary)
|
|
* ```
|
|
*/
|
|
export function generateUsername(email: string): string {
|
|
const [localPart] = email.split("@");
|
|
const randomSuffix = Math.random().toString(36).substring(2, 8); // Generate a random alphanumeric string
|
|
return `${localPart}.${randomSuffix}`;
|
|
}
|
|
|
|
/**
|
|
* Formats a date string to a human-readable format with type safety.
|
|
* @param date - The date string to format.
|
|
* @param options - Formatting options or a format string.
|
|
* @returns The formatted date string.
|
|
* @example
|
|
* // Using default format
|
|
* formatDate("2025-03-23")
|
|
*
|
|
* // Using a custom format string
|
|
* formatDate("2025-03-23", "yyyy-MM-dd")
|
|
*
|
|
* // Using formatting options
|
|
* formatDate("2025-03-23", { format: "MMMM do, yyyy", fallback: "Not available" })
|
|
*/
|
|
export const formatDate = (
|
|
date: string | Date | undefined | null,
|
|
options: DateFormatOptions | DateFormatPattern = { format: "PPpp" }
|
|
): string => {
|
|
if (!date) {
|
|
return typeof options === "string"
|
|
? "-"
|
|
: (options.fallback || "-");
|
|
}
|
|
|
|
const dateObj = date instanceof Date ? date : new Date(date);
|
|
|
|
// Handle invalid dates
|
|
if (isNaN(dateObj.getTime())) {
|
|
return typeof options === "string"
|
|
? "-"
|
|
: (options.fallback || "-");
|
|
}
|
|
|
|
if (typeof options === "string") {
|
|
return format(dateObj, options);
|
|
}
|
|
|
|
const { format: formatPattern = "PPpp", locale } = options;
|
|
|
|
return locale
|
|
? format(dateObj, formatPattern, { locale })
|
|
: format(dateObj, formatPattern);
|
|
};
|
|
|
|
export const copyItem = (item: string, options?: {
|
|
label?: string,
|
|
onSuccess?: () => void,
|
|
onError?: (error: unknown) => void
|
|
}) => {
|
|
if (!navigator.clipboard) {
|
|
const error = new Error("Clipboard not supported");
|
|
toast.error("Clipboard not supported");
|
|
options?.onError?.(error);
|
|
return;
|
|
}
|
|
|
|
if (!item) {
|
|
const error = new Error("Nothing to copy");
|
|
toast.error("Nothing to copy");
|
|
options?.onError?.(error);
|
|
return;
|
|
}
|
|
|
|
navigator.clipboard.writeText(item)
|
|
.then(() => {
|
|
const label = options?.label || item;
|
|
toast.success(`${label} copied to clipboard`);
|
|
options?.onSuccess?.();
|
|
})
|
|
.catch((error) => {
|
|
toast.error("Failed to copy to clipboard");
|
|
options?.onError?.(error);
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Formats a date string to a human-readable format with type safety.
|
|
* @param date - The date string to format.
|
|
* @param options - Formatting options or a format string.
|
|
* @returns The formatted date string.
|
|
* @example
|
|
* // Using default format
|
|
* formatDate("2025-03-23")
|
|
*
|
|
* // Using a custom format string
|
|
* formatDate("2025-03-23", "yyyy-MM-dd")
|
|
*
|
|
* // Using formatting options
|
|
* formatDate("2025-03-23", { format: "MMMM do, yyyy", fallback: "Not available" })
|
|
*/
|
|
export const formatDateWithFallback = (
|
|
date: string | Date | undefined | null,
|
|
options: DateFormatOptions | DateFormatPattern = { format: "PPpp" }
|
|
): string => {
|
|
if (!date) {
|
|
return typeof options === "string"
|
|
? "-"
|
|
: (options.fallback || "-");
|
|
}
|
|
|
|
const dateObj = date instanceof Date ? date : new Date(date);
|
|
|
|
// Handle invalid dates
|
|
if (isNaN(dateObj.getTime())) {
|
|
return typeof options === "string"
|
|
? "-"
|
|
: (options.fallback || "-");
|
|
}
|
|
|
|
if (typeof options === "string") {
|
|
return format(dateObj, options);
|
|
}
|
|
|
|
const { format: formatPattern = "PPpp", locale } = options;
|
|
|
|
return locale
|
|
? format(dateObj, formatPattern, { locale })
|
|
: format(dateObj, formatPattern);
|
|
}
|
|
|
|
export const formatDateWithLocale = (
|
|
date: string | Date | undefined | null,
|
|
options: DateFormatOptions | DateFormatPattern = { format: "PPpp" }
|
|
): string => {
|
|
if (!date) {
|
|
return typeof options === "string"
|
|
? "-"
|
|
: (options.fallback || "-");
|
|
}
|
|
|
|
const dateObj = date instanceof Date ? date : new Date(date);
|
|
|
|
// Handle invalid dates
|
|
if (isNaN(dateObj.getTime())) {
|
|
return typeof options === "string"
|
|
? "-"
|
|
: (options.fallback || "-");
|
|
}
|
|
|
|
if (typeof options === "string") {
|
|
return format(dateObj, options);
|
|
}
|
|
|
|
const { format: formatPattern = "PPpp", locale } = options;
|
|
|
|
return locale
|
|
? format(dateObj, formatPattern, { locale })
|
|
: format(dateObj, formatPattern);
|
|
};
|
|
|
|
/**
|
|
* Formats a date string to a human-readable format with type safety.
|
|
* @param date - The date string to format.
|
|
* @param options - Formatting options or a format string.
|
|
* @returns The formatted date string.
|
|
* @example
|
|
* // Using default format
|
|
* formatDate("2025-03-23")
|
|
*
|
|
* // Using a custom format string
|
|
* formatDate("2025-03-23", "yyyy-MM-dd")
|
|
*
|
|
* // Using formatting options
|
|
* formatDate("2025-03-23", { format: "MMMM do, yyyy", fallback: "Not available" })
|
|
*/
|
|
export const formatDateWithLocaleAndFallback = (
|
|
date: string | Date | undefined | null,
|
|
options: DateFormatOptions | DateFormatPattern = { format: "PPpp" }
|
|
): string => {
|
|
if (!date) {
|
|
return typeof options === "string"
|
|
? "-"
|
|
: (options.fallback || "-");
|
|
}
|
|
|
|
const dateObj = date instanceof Date ? date : new Date(date);
|
|
|
|
// Handle invalid dates
|
|
if (isNaN(dateObj.getTime())) {
|
|
return typeof options === "string"
|
|
? "-"
|
|
: (options.fallback || "-");
|
|
}
|
|
|
|
if (typeof options === "string") {
|
|
return format(dateObj, options);
|
|
}
|
|
|
|
const { format: formatPattern = "PPpp", locale } = options;
|
|
|
|
return locale
|
|
? format(dateObj, formatPattern, { locale })
|
|
: format(dateObj, formatPattern);
|
|
}
|
|
|
|
/**
|
|
* Generates a full name from first and last names.
|
|
* @param firstName - The first name.
|
|
* @param lastName - The last name.
|
|
* @returns The full name or "User" if both names are empty.
|
|
*/
|
|
export const getFullName = (firstName: string, lastName: string): string => {
|
|
return `${firstName} ${lastName}`.trim() || "User";
|
|
}
|
|
|
|
/**
|
|
* Generates initials for a user based on their first and last names.
|
|
* @param firstName - The first name.
|
|
* @param lastName - The last name.
|
|
* @param email - The email address.
|
|
* @returns The initials or "U" if both names are empty.
|
|
*/
|
|
export const getInitials = (firstName: string, lastName: string, email: string): string => {
|
|
if (firstName && lastName) {
|
|
return `${firstName[0]}${lastName[0]}`.toUpperCase();
|
|
}
|
|
if (firstName) {
|
|
return firstName[0].toUpperCase();
|
|
}
|
|
if (email) {
|
|
return email[0].toUpperCase();
|
|
}
|
|
return "U";
|
|
}
|
|
|