MIF_E31221222/sigap-website/app/_utils/common.ts

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);
});
};