Files
nobat724_front/helper/index.js
T

735 lines
20 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { toast } from "react-toastify";
import Cookies from "js-cookie";
import moment from "moment-jalaali";
import "moment-timezone";
// Data
import specialties from "@/data/specialties.json";
import states from "@/data/state.json";
import cities from "@/data/city.json";
export const numberToArStyle = (num) => num?.toLocaleString("ar-AE") || "";
export const isActiveURL = (link, name) => link === name;
// نگاشت پاسخ API بلاگ (image_url/tags/created_at/body/author-object) به شکلی که
// کامپوننت‌های بلاگ انتظار دارند (images[{url}]/tag[{name}]/created/body.value/author-string).
export const normalizeBlog = (blog) => {
if (!blog) return null;
return {
...blog,
images: blog.image_url ? [{ url: blog.image_url }] : [],
tag: Array.isArray(blog.tags)
? blog.tags.map((t) => (typeof t === "string" ? { name: t } : t))
: [],
created: blog.created_at ?? blog.created ?? null,
body:
blog.body && typeof blog.body === "object"
? blog.body
: { value: blog.body ?? "" },
author:
blog.author && typeof blog.author === "object"
? blog.author.name
: blog.author ?? null,
};
};
// تبدیل مسیر نسبی تصویر (/uploads/...) به URL کامل backend.
// مسیرهای absolute (http...) و asset های محلی (/assets، /default) دست‌نخورده می‌مانند.
export const imageUrl = (url, fallback = "/assets/images/user.png") => {
if (!url) return fallback;
if (/^https?:\/\//.test(url)) return url;
if (url.startsWith("/uploads")) {
const base = process.env.NEXT_PUBLIC_API_URL || "";
return `${base}${url}`;
}
return url;
};
// نام پزشک با پیشوند «دکتر»، بدون تکرار. بعضی رکوردها خودشان با «دکتر»/«دکتر.»
// ذخیره شده‌اند؛ بدون این نرمال‌سازی خروجی «دکتر دکتر ...» می‌شود.
export const doctorTitle = (name) => {
const clean = (name || "").trim().replace(/^(دکتر|دكتر)[.،:]?\s+/, "");
return clean ? `دکتر ${clean}` : "";
};
export const convertToJalali = (date) => {
const currentDate = date;
const jalaliDate = moment(currentDate).format("jYYYY/jM/jD");
const jalaliYear = moment(jalaliDate, "jYYYY/jM/jD").jYear();
const jalaliMonth = moment(jalaliDate, "jYYYY/jM/jD").jMonth() + 1;
const jalaliDay = moment(jalaliDate, "jYYYY/jM/jD").jDate();
return `${jalaliYear}/${jalaliMonth}/${jalaliDay}`;
};
export const convertTimestampToJalali = (timestamp) => {
if (!timestamp) return "--";
const date = moment.unix(timestamp);
return date.format("jYYYY/jMM/jDD");
};
export const convertTimestampToTime = (timestamp) => {
if (!timestamp) return "--";
const date = moment.unix(timestamp);
return date.format("HH:mm");
};
export const handleTwoLength = (value) =>
String(value).length === 1 ? `0${value}` : value;
export const checkAllValues = (data) => {
for (let key in data) {
const item = data[key];
if (typeof item === "object" && item !== null) {
if ("value" in item) {
if (!item.value) {
return false;
}
} else {
if (!checkAllValues(item)) {
return false;
}
}
}
}
return true;
};
export const checkTimes = (arr) => {
return arr.map((day) => {
const hasMorningTime = day.morning_time.some((time) => time !== "");
const hasEveningTime = day.evening_time.some((time) => time !== "");
return hasMorningTime && hasEveningTime;
});
};
export const uploadImage = async (event) => {
let obj = {
file: "",
blob: "",
};
const file = event.target.files[0];
if (file) {
obj.file = file;
const readFileAsDataURL = (file) => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = (error) => reject(error);
reader.readAsDataURL(file);
});
};
try {
obj.blob = await readFileAsDataURL(file);
return obj;
} catch (error) {
console.error("Error reading file: ", error);
throw error;
}
} else {
throw new Error("No file selected");
}
};
export const alert = (type, text, prop) => {
toast[type](
<div className="h-full w-full flex flex-col items-start justify-center gap-[13px]">
<p className="text-[14px] font-medium">
پیغام{" "}
{type === "error"
? "خطا"
: type === "warning"
? "هشدار"
: type === "info"
? "اعلام"
: "موفقیت"}
</p>
<p className="text-[14px] font-normal">{text}</p>
</div>,
{ prop }
);
};
export const formatPhoneNumber = (input) => {
if (typeof input !== "string") input = String(input);
const normalized = input
.replace(/[\u06F0-\u06F9]/g, (d) => String(d.charCodeAt(0) - 0x06f0))
.replace(/[\u0660-\u0669]/g, (d) => String(d.charCodeAt(0) - 0x0660));
const digits = normalized.replace(/\D/g, "");
const trimmed = digits.substring(0, 9);
const match = trimmed.match(/^(\d{0,2})(\d{0,3})(\d{0,4})$/);
if (!match) return trimmed;
return [match[1], match[2], match[3]].filter(Boolean).join(" ");
};
export function validatePhoneNumber(input) {
if (!input) {
return { valid: false, text: "شماره موبایل نمی‌تواند خالی باشد." };
}
// چک کردن اینکه فقط اعداد انگلیسی باشد
const hasNonEnglishDigits = /[^0-9]/.test(input);
if (hasNonEnglishDigits) {
return { valid: false, text: "فقط از اعداد انگلیسی استفاده کنید." };
}
if (input.length !== 11) {
return { valid: false, text: "شماره موبایل باید دقیقا 11 رقم باشد." };
}
const isValid = /^09\d{9}$/.test(input);
if (!isValid) {
return { valid: false, text: "شماره موبایل نامعتبر است." };
}
return { valid: true, text: null };
}
export const searchOnList = (list, value, name) => {
let newList = list;
newList = list.filter((item) => item[name]?.toLowerCase()?.includes(value));
return newList;
};
export function clearFilterParams(router, listRemove) {
const currentParams = new URLSearchParams(window.location.search);
const keysToRemove = listRemove;
keysToRemove.forEach((key) => currentParams.delete(key));
const queryString = currentParams.toString();
const newUrl = queryString ? `/doctors?${queryString}` : "/doctors";
router.push(newUrl);
}
export function clearDoctorClinicParams(router, slug) {
const clinicslug = slug;
const newUrl = `/clinic/${clinicslug}`;
router.push(newUrl)
}
export const filterList = (data) => {
const parentList = specialties.filter((item) => !item.parent_id);
const childrenList = specialties.filter((item) => item.parent_id);
const filteredChildrenList =
data && data.category
? childrenList.filter(
(item) => String(item.parent_id) === String(data.category.id)
)
: [];
return {
parentList: parentList,
childrenList: filteredChildrenList,
};
};
export function getCleanNumberValue(value, defaultValue = 0) {
if (typeof value !== "string") value = String(value);
const persianArabicToEnglish = value
.replace(/[\u06F0-\u06F9]/g, (d) => String(d.charCodeAt(0) - 0x06f0))
.replace(/[\u0660-\u0669]/g, (d) => String(d.charCodeAt(0) - 0x0660));
const cleaned = persianArabicToEnglish.replace(/[^0-9.]/g, "");
const number = parseFloat(cleaned);
return isNaN(number) ? defaultValue : number;
}
export function hasDataChanged(previousData, newData) {
const oldDataString = JSON.stringify(
previousData,
Object.keys(previousData).sort()
);
const newDataString = JSON.stringify(newData, Object.keys(newData).sort());
return oldDataString !== newDataString;
}
export const getParsedUserInfo = () => {
const user = Cookies.get("userInfo");
if (!user) return null;
try {
return JSON.parse(user);
} catch {
return null;
}
};
export const handleTimeExpiresToken = (expires_in) => {
const accessTokenExpires = new Date();
accessTokenExpires.setSeconds(accessTokenExpires.getSeconds() + expires_in);
const refreshTokenExpires = new Date();
refreshTokenExpires.setDate(refreshTokenExpires.getDate() + 30);
return {
accessTokenExpires,
refreshTokenExpires,
};
};
export const removeAdditionalKeysDashboard = (information) => {
// فقط متادیتای سمت فرانت حذف می‌شود؛ national_code باید ارسال شود تا قابل ثبت/آپدیت باشد.
const {
changed,
created,
id,
status,
prev_data,
uuid,
...usedKays
} = information;
return usedKays;
};
export const changeDateType = (data, toTimeStamp) => {
const newData = { ...data };
const birthday = newData.birthday;
if (toTimeStamp) {
const m = moment(birthday, "jYYYY/jMM/jDD");
newData.birthday = m.unix();
} else {
newData.birthday = moment.unix(birthday).format("jYYYY/jMM/jDD");
}
return newData;
};
export const removeTokenHead = {
headers: {
Authorization: "",
},
};
export const dateToTimestamp = (date) => {
// تنظیم timezone به تهران
const tehranMoment = date.clone().tz("Asia/Tehran").startOf("day");
// Get the Unix timestamp in seconds
const inSeconde = tehranMoment.unix();
return inSeconde;
};
export const degreeVal = [
{ name: "پزشک عمومی", val: "general" },
{ name: "پزشک متخصص", val: "specialist" },
{ name: "پزشک فوق تخصص", val: "subspecialistplus" },
];
export const addLabelToList = (list) =>
list.map((item) => {
return {
...item,
label: item.name,
};
});
export const QueryForDoctorsFilter = (newFilter) => {
const query = {};
// 🔹 active => only when value === 1
if (newFilter.active === 1) {
query.active = 1;
}
// 🔹 specialty or category
if (newFilter.specialty) {
query.specialty = newFilter.specialty.name;
} else if (newFilter.category) {
query.specialty = newFilter.category.name;
}
// 🔹 city
if (newFilter.city) {
query.city = newFilter.city.name;
}
// 🔹 state
if (newFilter.state) {
query.state = newFilter.state.name;
}
// 🔹 degree (only if not "همه موارد")
if (newFilter.degree && newFilter.degree !== "همه موارد") {
query.degree = newFilter.degree;
}
// 🔹 gender (only if not "هر دو")
if (newFilter.gender && newFilter.gender !== "هر دو") {
query.gender = newFilter.gender;
}
// 🔹 name (only if has value)
if (newFilter.name && newFilter.name.trim() !== "") {
query.name = newFilter.name;
}
// 🔹 sort => only if value is 3,4,5
if ([3, 4, 5].includes(Number(newFilter.sort))) {
// query.sort = newFilter.sort === 3 ? "ASC" : "DESC";
query.sort = newFilter.sort;
}
return query;
};
export const QueryForClinicDoctorFilter = (newFilter) => {
const query = {};
// 🔹 active => only when value === 1
if (newFilter.active === 1) {
query.active = 1;
}
// 🔹 specialty or category
if (newFilter.specialty) {
query.specialty = newFilter.specialty.name;
} else if (newFilter.category) {
query.specialty = newFilter.category.name;
}
// 🔹 degree (only if not "همه موارد")
if (newFilter.degree && newFilter.degree !== "همه موارد") {
query.degree = newFilter.degree;
}
// 🔹 gender (only if not "هر دو")
if (newFilter.gender && newFilter.gender !== "هر دو") {
query.gender = newFilter.gender;
}
// 🔹 name (only if has value)
if (newFilter.name && newFilter.name.trim() !== "") {
query.name = newFilter.name;
}
// 🔹 sort => only if value is 3,4,5
if ([3, 4, 5].includes(Number(newFilter.sort))) {
// query.sort = newFilter.sort === 3 ? "ASC" : "DESC";
query.sort = newFilter.sort;
}
return query;
}
export const QueryForDoctorsReq = (newFilter) => {
const params = {};
if (newFilter.active === 1) params.active = 1;
if (newFilter.specialty?.id) {
params.specialty_id = newFilter.specialty.id;
} else if (newFilter.category?.id) {
params.specialty_id = newFilter.category.id;
}
if (newFilter.city?.id) params.city_id = newFilter.city.id;
if (newFilter.state?.id) params.state_id = newFilter.state.id;
if (newFilter.degree && newFilter.degree !== "همه موارد")
switch (newFilter.degree) {
case "کارشناس":
params.degree = "expert";
break;
case "پزشک عمومی":
params.degree = "general";
break;
case "پزشک متخصص":
params.degree = "specialist";
break;
case "پزشک فوق تخصص":
params.degree = "subspecialistplus";
break;
default:
break;
}
if (newFilter.gender && newFilter.gender !== "هر دو")
params.gender = newFilter.gender === "مرد" ? "man" : "woman";
if (newFilter.name) params.name = newFilter.name;
if (newFilter.sort) {
if (newFilter.sort === 3) params.sort = "ASC";
else if (newFilter.sort === 4 || newFilter.sort === 5) params.sort = "DESC";
}
return params;
};
export const QueryForDoctorsClinicReq = (newFilter) => {
const params = {};
if (newFilter.active === 1) params.active = 1;
if (newFilter.specialty?.id) {
params.specialty = newFilter.specialty.id;
} else if (newFilter.category?.id) {
params.specialty = newFilter.category.id;
}
if (newFilter.degree && newFilter.degree !== "همه موارد")
switch (newFilter.degree) {
case "کارشناس":
params.degree = "expert";
break;
case "پزشک عمومی":
params.degree = "general";
break;
case "پزشک متخصص":
params.degree = "specialist";
break;
case "پزشک فوق تخصص":
params.degree = "subspecialistplus";
break;
default:
break;
}
if (newFilter.gender && newFilter.gender !== "هر دو")
params.gender = newFilter.gender === "مرد" ? "man" : "woman";
if (newFilter.name) params.name = newFilter.name;
if (newFilter.sort) {
if (newFilter.sort === 3) params.sort = "ASC";
else if (newFilter.sort === 4 || newFilter.sort === 5) params.sort = "DESC";
}
return params;
}
export const buildDoctorParams = (searchParams) => {
const params = {};
// 🔹 active
if (searchParams.active && Number(searchParams.active) === 1) {
params.active = 1;
}
// 🔹 specialty (find by name in specialties.json)
if (searchParams.specialty) {
const spec = specialties.find((s) => s.name === searchParams.specialty);
if (spec) {
params.specialty_id = spec.id;
}
}
// 🔹 city (find by name in city.json)
if (searchParams.city) {
const cityObj = cities.find((c) => c.name === searchParams.city);
if (cityObj) {
params.city_id = cityObj.id;
}
}
// 🔹 state (find by name in state.json)
if (searchParams.state) {
const stateObj = states.find((s) => s.name === searchParams.state);
if (stateObj) {
params.state_id = stateObj.id;
}
}
// 🔹 degree → convert fa → en
if (searchParams.degree) {
switch (searchParams.degree) {
case "کارشناس":
params.degree = "expert";
break;
case "پزشک عمومی":
params.degree = "general";
break;
case "پزشک متخصص":
params.degree = "specialist";
break;
case "پزشک فوق تخصص":
params.degree = "subspecialistplus";
break;
default:
break;
}
}
// 🔹 gender
if (searchParams.gender) {
if (searchParams.gender === "مرد") params.gender = "man";
if (searchParams.gender === "زن") params.gender = "woman";
}
// 🔹 name
if (searchParams.name) {
params.name = searchParams.name;
}
// 🔹 sort (3 = ASC, 4|5 = DESC)
if (searchParams.sort) {
const sortNum = Number(searchParams.sort);
if (sortNum === 3) params.sort = "ASC";
else if ([4, 5].includes(sortNum)) params.sort = "DESC";
}
// 🔹 page
params.page = searchParams.page || 1;
// 🔹 limit
params.limit = 12;
return params;
};
export const QueryForClinicsFilter = (searchParams) => {
const params = {};
// 🔹 specialty (find by name in specialties.json)
if (searchParams.specialty) {
const spec = specialties.find((s) => s.name === searchParams.specialty);
if (spec) {
params.specialty = spec.id;
}
}
// 🔹 city (find by name in city.json)
if (searchParams.city) {
const cityObj = cities.find((c) => c.name === searchParams.city.name);
if (cityObj) {
params.city = cityObj.id;
}
}
// 🔹 state (find by name in state.json)
if (searchParams.province) {
const stateObj = states.find((s) => s.name === searchParams.province.name);
if (stateObj) {
params.state = stateObj.id;
}
}
// 🔹 page
params.page = searchParams.page || 1;
// 🔹 limit
params.limit = 12;
return params;
};
export const buildClinicParams = (searchParams) => {
const params = {};
// 🔹 city (find by name in city.json)
if (searchParams.city) {
const cityObj = cities.find((c) => c.name === searchParams.city);
if (cityObj) {
params.city = cityObj.id;
}
}
// 🔹 state (find by name in state.json)
if (searchParams.state) {
const stateObj = states.find((s) => s.name === searchParams.state);
if (stateObj) {
params.state = stateObj.id;
}
}
// 🔹 specialty (find by name in specialties.json)
if (searchParams.specialty) {
const spec = specialties.find((s) => s.name === searchParams.specialty);
if (spec) {
params.specialty = spec.id;
}
}
// 🔹 page
params.page = searchParams.page || 1;
// 🔹 limit
params.limit = 12;
return params;
};
export function timeAgo(timestamp) {
const now = moment();
const then = moment.unix(timestamp);
const diffSeconds = now.diff(then, "seconds");
if (diffSeconds < 60) {
return diffSeconds === 0 ? "همین الان" : `${diffSeconds} ثانیه پیش`;
} else if (diffSeconds < 3600) {
const minutes = Math.floor(diffSeconds / 60);
return `${minutes} دقیقه پیش`;
} else if (diffSeconds < 86400) {
const hours = Math.floor(diffSeconds / 3600);
return `${hours} ساعت پیش`;
} else if (diffSeconds < 2592000) {
const days = Math.floor(diffSeconds / 86400);
return `${days} روز پیش`;
} else if (diffSeconds < 31104000) {
const months = Math.floor(diffSeconds / 2592000);
return `${months} ماه پیش`;
} else {
const years = Math.floor(diffSeconds / 31104000);
return `${years} سال پیش`;
}
}
export function isUserLoggedIn() {
// access_token در memory است نه کوکی؛ userInfo کوکیِ non-httpOnly است که هنگام لاگین ست می‌شود.
return !!Cookies.get("userInfo");
}
export function convertTimestampToPersianDateSimple(timestamp) {
const date = new Date(timestamp * 1000);
const options = {
timeZone: "Asia/Tehran",
calendar: "persian",
year: "numeric",
month: "2-digit",
day: "2-digit",
weekday: "long",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hour12: true,
};
return date.toLocaleString("fa-IR", options);
}
export function changeNumToDefault(str) {
if (!str) return "";
return str
.toString()
.replace(/[۰-۹]/g, d => "۰۱۲۳۴۵۶۷۸۹".indexOf(d))
.replace(/[٠-٩]/g, d => "٠١٢٣٤٥٦٧٨٩".indexOf(d));
}
// اعتبارسنجی کد ملی ایران: ۱۰ رقم + الگوریتم رقم کنترلی.
export const isValidIranNationalCode = (input) => {
if (!input) return false;
const code = String(input).replace(/\D/g, "");
if (!/^\d{10}$/.test(code)) return false;
// کدهای با ارقام یکسان (مثل 0000000000) نامعتبرند
if (/^(\d)\1{9}$/.test(code)) return false;
const check = +code[9];
let sum = 0;
for (let i = 0; i < 9; i++) sum += +code[i] * (10 - i);
const r = sum % 11;
return r < 2 ? check === r : check === 11 - r;
};