Files
nobat724_front/helper/index.js
T
hamedandClaude Opus 4.8 5067824f28 feat(panel): connect turns/user-account/add-doctor to real data
- انتقال adapterهای نماینده به lib/representationAdapters (server-safe،
  بدون وابستگی client مثل js-cookie/react-toastify)
- turns: لیست از daily[] داشبورد ماهانه (ستون نام/تخصص خالی، بدون داده ساختگی)
- user-account: حساب بانکی واقعی از bank_account نماینده (map به آرایه تک‌کارته)
- add-doctor: حذف import mock مرده (کامپوننت data مصرف نمی‌کرد)
- رفع dead import اشتباه از turns/page در clinic/doctors که build را می‌شکست

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 00:06:01 +03:30

678 lines
17 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;
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);
const childrenList = specialties.filter((item) => item.parent);
const filteredChildrenList =
data && data.category
? childrenList.filter((item) => item.parent === 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) => {
const {
national_code,
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 = newFilter.specialty.id;
} else if (newFilter.category?.id) {
params.specialty = newFilter.category.id;
}
if (newFilter.city?.id) params.city = newFilter.city.id;
if (newFilter.state?.id) params.state = 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 = 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 = 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;
}
}
// 🔹 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() {
const userInfo = Cookies.get("access_token");
return !!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));
}