443 lines
13 KiB
JavaScript
443 lines
13 KiB
JavaScript
"use client";
|
|
import { useState } from "react";
|
|
import * as XLSX from "xlsx";
|
|
|
|
const validatePhoneNumber = (phone) => {
|
|
// Regex for exactly 10 digits
|
|
const phoneRegex = /^\d{10}$/;
|
|
return phoneRegex.test(phone);
|
|
};
|
|
export const validateForm = (formData, validationRules, setErrMsg) => {
|
|
const errors = {};
|
|
|
|
Object.keys(validationRules).forEach((field) => {
|
|
const rules = validationRules[field];
|
|
const value = formData[field];
|
|
|
|
if (
|
|
rules.required &&
|
|
(!value || (typeof value === "string" && value.trim() === ""))
|
|
) {
|
|
errors[field] = "Enter This Field";
|
|
} else if (rules.email && !validateEmail(value)) {
|
|
errors[field] = "Invalid Email";
|
|
} else if (rules.custom && !rules.custom(value)) {
|
|
errors[field] = rules.customMessage || "Invalid value";
|
|
} else if (rules.fileType && value && value instanceof File) {
|
|
// Validate file type
|
|
if (!rules.fileType.includes(value.type)) {
|
|
errors[field] = "Invalid file type";
|
|
}
|
|
// Validate file size
|
|
if (rules.fileSize && value.size > rules.fileSize) {
|
|
errors[field] = "File is too large";
|
|
}
|
|
} else if (rules.phoneNumber && !validatePhoneNumber(value)) {
|
|
// Validate phone number
|
|
errors[field] = "Invalid phone number. Must be exactly 10 digits.";
|
|
}
|
|
});
|
|
|
|
setErrMsg(errors);
|
|
return Object.keys(errors).length === 0; // Return true if no errors
|
|
};
|
|
|
|
const validateEmail = (email) => {
|
|
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
return emailPattern.test(email);
|
|
};
|
|
|
|
export const FormField = ({
|
|
label,
|
|
type,
|
|
name,
|
|
value,
|
|
onChange,
|
|
error,
|
|
options,
|
|
className,
|
|
onSubmit,
|
|
accept,
|
|
placeholder,
|
|
required,
|
|
checked,
|
|
ref,
|
|
style,
|
|
disabled,
|
|
}) => {
|
|
const [showPassword, setShowPassword] = useState(false);
|
|
|
|
const handleTogglePasswordVisibility = () => {
|
|
setShowPassword(!showPassword);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<div className="relative">
|
|
{label && (
|
|
<label style={{ paddingRight: "20px" }}>
|
|
{label} {required && <span style={{ color: "red" }}>*</span>}
|
|
</label>
|
|
)}
|
|
|
|
{type === "select" ? (
|
|
<select
|
|
name={name}
|
|
onChange={onChange}
|
|
value={value}
|
|
className={className}
|
|
style={style}
|
|
>
|
|
<option value="" disabled>
|
|
Select {placeholder ? placeholder : label}
|
|
</option>
|
|
{options?.map((option, index) => (
|
|
<option key={index} value={option.value}>
|
|
{option.label}
|
|
</option>
|
|
))}
|
|
</select>
|
|
) : type === "selectbyname" ? (
|
|
<select
|
|
name={name}
|
|
onChange={onChange}
|
|
value={value}
|
|
className={className}
|
|
style={style}
|
|
>
|
|
<option value="" disabled>
|
|
Select {placeholder}
|
|
</option>
|
|
{options.map((option, index) => (
|
|
<option key={index} value={option.label}>
|
|
{option.label}
|
|
</option>
|
|
))}
|
|
</select>
|
|
) : type === "file" ? (
|
|
<input
|
|
type="file"
|
|
name={name}
|
|
ref={ref}
|
|
accept={accept}
|
|
onChange={onChange}
|
|
className={className}
|
|
/>
|
|
) : type === "password" ? (
|
|
<div className="flex items-center" style={{ position: "relative" }}>
|
|
<input
|
|
type={showPassword ? "text" : "password"}
|
|
name={name}
|
|
onChange={onChange}
|
|
value={value}
|
|
className={`${className} flex-grow`}
|
|
/>
|
|
<button
|
|
type="button"
|
|
onClick={handleTogglePasswordVisibility}
|
|
className="ml-2"
|
|
style={{ position: "absolute", right: "10px", top: "22%" }}
|
|
aria-label={showPassword ? "Hide password" : "Show password"}
|
|
>
|
|
{showPassword ? (
|
|
<i className="fas fa-eye-slash"></i>
|
|
) : (
|
|
<i className="fas fa-eye"></i>
|
|
)}
|
|
</button>
|
|
</div>
|
|
) : type === "email" ? (
|
|
<input
|
|
type="email"
|
|
name={name}
|
|
onChange={onChange}
|
|
value={value}
|
|
className={className}
|
|
disabled={disabled}
|
|
/>
|
|
) : type === "textarea" ? (
|
|
<textarea
|
|
name={name}
|
|
placeholder={label || placeholder}
|
|
onChange={onChange}
|
|
value={value}
|
|
className={className}
|
|
style={style}
|
|
></textarea>
|
|
) : type === "date" ? (
|
|
<input
|
|
type="date"
|
|
name={name}
|
|
onChange={onChange}
|
|
placeholder={placeholder ? placeholder : label}
|
|
value={value}
|
|
className={className}
|
|
style={style}
|
|
/>
|
|
) : type === "datetime" ? (
|
|
<input
|
|
type="datetime-local"
|
|
name={name}
|
|
onChange={onChange}
|
|
placeholder={placeholder ? placeholder : label}
|
|
value={value}
|
|
className={className}
|
|
style={style}
|
|
/>
|
|
) : type === "tel" ? (
|
|
<input
|
|
type="tel"
|
|
name={name}
|
|
onChange={onChange}
|
|
value={value}
|
|
className={className}
|
|
pattern="\d{10}"
|
|
maxLength="10"
|
|
disabled={disabled}
|
|
/>
|
|
) : type === "radio" ? (
|
|
<div className="row">
|
|
{options?.map((option, index) => (
|
|
<div
|
|
key={index}
|
|
className="form-radio col-4"
|
|
style={{ display: "flex", alignItems: "center" }}
|
|
>
|
|
<label
|
|
htmlFor={`${name}-${option.value}`}
|
|
style={{ marginRight: "5px", color: "black" }}
|
|
>
|
|
{option.label}
|
|
</label>
|
|
<input
|
|
style={{ width: "15%" }}
|
|
type="radio"
|
|
name={name}
|
|
value={option.value}
|
|
checked={value === option.value}
|
|
onChange={onChange}
|
|
className={className}
|
|
id={`${name}-${option.value}`}
|
|
/>
|
|
</div>
|
|
))}
|
|
</div>
|
|
) : type === "checkbox" ? (
|
|
<input
|
|
type="checkbox"
|
|
name={name}
|
|
onChange={onChange}
|
|
checked={checked}
|
|
className="form-checkbox"
|
|
id={name}
|
|
/>
|
|
) : (
|
|
<input
|
|
type={type}
|
|
name={name}
|
|
onChange={onChange}
|
|
value={value}
|
|
className={`${className} custom-input`}
|
|
placeholder={placeholder}
|
|
style={style}
|
|
disabled={disabled}
|
|
/>
|
|
)}
|
|
{error && (
|
|
<p className="error" style={{ color: "red", paddingTop: "3px" }}>
|
|
{error}
|
|
</p>
|
|
)}
|
|
</div>
|
|
<div>
|
|
{onSubmit && (
|
|
<button className="applicants-search-btn" onClick={onSubmit}>
|
|
Search
|
|
</button>
|
|
)}
|
|
</div>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export const XLFormat = (data) => {
|
|
// Create a new workbook and add a worksheet
|
|
const wb = XLSX.utils.book_new();
|
|
const ws = XLSX.utils.json_to_sheet(data);
|
|
|
|
// Add the worksheet to the workbook
|
|
XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
|
|
|
|
// Write the workbook and trigger a download
|
|
XLSX.writeFile(wb, "Applicants Data.xlsx");
|
|
};
|
|
|
|
|
|
export const downloadExcel = (data) => {
|
|
if (!data || typeof data !== 'object') {
|
|
console.error("Invalid data: Data should be an object.");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// Convert the object to an array of objects
|
|
const formattedData = Object.keys(data).map(key => {
|
|
return { [key]: data[key] }; // Convert object to an array of key-value pairs
|
|
});
|
|
|
|
// Now we have an array of objects, each object has a key-value pair from the original object
|
|
const ws = XLSX.utils.json_to_sheet(formattedData); // Convert JSON to worksheet
|
|
const wb = XLSX.utils.book_new(); // Create a new workbook
|
|
XLSX.utils.book_append_sheet(wb, ws, 'Events'); // Append worksheet to workbook
|
|
|
|
// Create a Blob with the Excel file and trigger download
|
|
XLSX.writeFile(wb, 'event_data.xlsx');
|
|
} catch (error) {
|
|
console.error("Error during Excel download:", error);
|
|
}
|
|
};
|
|
|
|
export const useSetState = (initialState) => {
|
|
const [state, setState] = useState(initialState);
|
|
|
|
const newSetState = (newState) => {
|
|
setState((prevState) => ({ ...prevState, ...newState }));
|
|
};
|
|
return [state, newSetState];
|
|
};
|
|
|
|
export const Dropdown = (arr, label) => {
|
|
const array = arr?.map((item) => ({ value: item?.id, label: item[label] }));
|
|
return array;
|
|
};
|
|
|
|
export const questionTemplates = {
|
|
accommodation: {
|
|
question: "Do you require accommodation?",
|
|
helpText: "Let us know if you need accommodation.",
|
|
options: "",
|
|
is_faf: "Yes",
|
|
},
|
|
food: {
|
|
question: "What is your food preference?",
|
|
helpText: "Please specify your dietary preference.",
|
|
options: "Veg, Non-Veg",
|
|
is_faf: "No",
|
|
},
|
|
tshirt: {
|
|
question: "What is your T-Shirt size?",
|
|
helpText: "Please select your T-Shirt size.",
|
|
options: "S, M, L, XL, XXL",
|
|
is_faf: "Yes",
|
|
},
|
|
custom: {
|
|
question: "",
|
|
helpText: "",
|
|
options: "",
|
|
is_faf: "No",
|
|
},
|
|
};
|
|
|
|
export const transformedQuestions = (questions) => {
|
|
return questions.map((q) => ({
|
|
question: q.question,
|
|
helpText: q.helpText,
|
|
options: q.options,
|
|
is_faf: q.isMandatory === "Yes" ? true : false,
|
|
}));
|
|
};
|
|
|
|
export const getFileNameFromUrl = (url) => {
|
|
console.log("url: ", url);
|
|
const urlObject = new URL(url);
|
|
const pathname = urlObject.pathname;
|
|
|
|
// Extract the filename (e.g., doctor_dDm0mWx.jpg)
|
|
const filename = pathname.substring(pathname.lastIndexOf("/") + 1);
|
|
|
|
// Extract the file extension (e.g., jpg)
|
|
const fileExtension = filename.split(".").pop();
|
|
|
|
// Create a dummy file for demonstration purposes
|
|
const fileData = new Blob([], { type: `image/${fileExtension}` });
|
|
|
|
const file = new File([fileData], filename, {
|
|
type: `image/${fileExtension}`,
|
|
lastModified: Date.now(),
|
|
});
|
|
|
|
console.log("File object: ", file);
|
|
return file;
|
|
};
|
|
|
|
export const TruncatedContent = (content, length) => {
|
|
return content?.length > length
|
|
? content.substring(0, length) + "..."
|
|
: content;
|
|
};
|
|
|
|
export const ShortFormatedDate = (data) => {
|
|
const date = new Date(data);
|
|
const options = { month: "short", day: "numeric" };
|
|
return date.toLocaleDateString("en-US", options);
|
|
};
|
|
|
|
export const formattedDate = (data) =>
|
|
new Date(data).toLocaleDateString("en-US", {
|
|
year: "numeric",
|
|
month: "long",
|
|
day: "numeric",
|
|
});
|
|
|
|
export const formattedDateTime = (data) => {
|
|
const date = new Date(data);
|
|
return date.toLocaleString("en-US", {
|
|
year: "numeric",
|
|
month: "long",
|
|
day: "numeric",
|
|
hour: "2-digit", // Hour in 2 digits
|
|
minute: "2-digit", // Minute in 2 digits
|
|
second: "2-digit", // Second in 2 digits
|
|
hour12: true, // 12-hour format (AM/PM)
|
|
});
|
|
};
|
|
|
|
export const getFormattedDateTime = (start_date, start_time) => {
|
|
if (start_date && start_time) {
|
|
// Combine the date and time into the format YYYY-MM-DDTHH:mm
|
|
const formattedDateTime = `${start_date}T${start_time.substring(0, 5)}`;
|
|
|
|
console.log("Formatted DateTime:", formattedDateTime);
|
|
|
|
return formattedDateTime; // Returns the formatted datetime string
|
|
}
|
|
return null; // Return null if date or time is missing
|
|
};
|
|
|
|
|
|
export const convertTo12HourFormat = (time) => {
|
|
if (!time) return ''; // If time is not available, return an empty string
|
|
|
|
// Parse the time into hours and minutes
|
|
const [hours, minutes] = time.split(':');
|
|
|
|
let hoursIn12HourFormat = parseInt(hours, 10); // Convert hours to a number
|
|
const suffix = hoursIn12HourFormat >= 12 ? 'PM' : 'AM'; // Determine AM/PM
|
|
hoursIn12HourFormat = hoursIn12HourFormat % 12; // Convert 24-hour to 12-hour format
|
|
if (hoursIn12HourFormat === 0) hoursIn12HourFormat = 12; // Handle midnight case
|
|
|
|
// Format the time as a string
|
|
return `${hoursIn12HourFormat}:${minutes} ${suffix}`;
|
|
};
|
|
|
|
|
|
export const formatForGoogleCalendar = (date, time) => {
|
|
// Combine start date and time into one string
|
|
const startDateTime = new Date(`${date}T${time}`);
|
|
|
|
// Convert to the format required by Google Calendar: YYYYMMDDTHHmmSSZ
|
|
const googleCalendarTime = startDateTime.toISOString().replace(/[-:]/g, '').split('.')[0];
|
|
|
|
return googleCalendarTime;
|
|
};
|