150 lines
4.2 KiB
TypeScript
150 lines
4.2 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 handleCopyItem = (item: string, options?: {
|
|
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(() => {
|
|
toast.success("Copied to clipboard");
|
|
options?.onSuccess?.();
|
|
})
|
|
.catch((error) => {
|
|
toast.error("Failed to copy to clipboard");
|
|
options?.onError?.(error);
|
|
});
|
|
}; |