Descriptive . 33.

This commit is contained in:
yznahmad 2025-07-30 18:41:05 +03:00
parent 386241b488
commit 0f7d782cd3
7 changed files with 77 additions and 28 deletions

View File

@ -49,7 +49,8 @@ export async function POST(req:Request)
} | null = payload.bodyState as { } | null = payload.bodyState as {
startBodyForm: String, startBodyForm: String,
startWeight: Number, startWeight: Number,
} | null; } | null,
subscriptionDate : string | null = payload.subscriptionDate as string | null;
// Validate required fields // Validate required fields
if (!firstName || !lastName || !phone) { if (!firstName || !lastName || !phone) {
@ -111,24 +112,24 @@ export async function POST(req:Request)
// Calculate total monthly pay // Calculate total monthly pay
const payMonth = servicesDocs.reduce((total, service) => total + service.price, 0) const payMonth = servicesDocs.reduce((total, service) => total + service.price, 0)
// Declare needed variables // current time variables - use custom date if provided, otherwise use current date
let current_date = new Date(), const subscription_date = subscriptionDate ? new Date(subscriptionDate) : new Date();
current_date_unix = Math.floor(Date.now() / 1000), const subscription_date_unix = Math.floor(subscription_date.getTime() / 1000);
planDelay_unix = planDelay ? planDelay * 2592000: 0 * 2592000, const planDelay_unix = planDelay * 2592000;
planExpAt = new Date((current_date_unix + planDelay_unix) * 1000); const planExpAt = new Date((subscription_date_unix + planDelay_unix) * 1000);
// Create services array with per-service subscription details // Create services array with per-service subscription details
const servicesArray = servicesDocs.map(service => ({ const servicesArray = servicesDocs.map(service => ({
serviceID: service._id.toString(), serviceID: service._id.toString(),
serviceName: service.name, serviceName: service.name,
registeredAt: current_date.toUTCString(), registeredAt: subscription_date.toUTCString(),
registeredAt_unix: current_date_unix, registeredAt_unix: subscription_date_unix,
planDelay: planDelay, planDelay: planDelay,
planDelay_unix: planDelay_unix, planDelay_unix: planDelay_unix,
planExpAt: planExpAt.toUTCString(), planExpAt: planExpAt.toUTCString(),
planExpAt_unix: current_date_unix + planDelay_unix, planExpAt_unix: subscription_date_unix + planDelay_unix,
planUpdatedAt: current_date.toUTCString(), planUpdatedAt: subscription_date.toUTCString(),
planUpdatedAt_unix: current_date_unix, planUpdatedAt_unix: subscription_date_unix,
active: true, active: true,
})) }))
@ -155,15 +156,15 @@ export async function POST(req:Request)
services: servicesArray, services: servicesArray,
gendre, gendre,
bodyState, bodyState,
registerAt: current_date.toUTCString(), registerAt: subscription_date.toUTCString(),
registerAt_unix: current_date_unix, registerAt_unix: subscription_date_unix,
// Global subscription status (derived from services) // Global subscription status (derived from services)
planUpdatedAt: current_date.toUTCString(), planUpdatedAt: subscription_date.toUTCString(),
planUpdatedAt_unix: current_date_unix, planUpdatedAt_unix: subscription_date_unix,
planDelay, planDelay,
planDelay_unix: planDelay_unix, planDelay_unix: planDelay_unix,
planExpAt: planExpAt.toUTCString(), planExpAt: planExpAt.toUTCString(),
planExpAt_unix: current_date_unix + planDelay_unix, planExpAt_unix: subscription_date_unix + planDelay_unix,
active: true, active: true,
}) })
@ -180,7 +181,7 @@ export async function POST(req:Request)
name: `New Member Subscription - ${firstName} ${lastName}`, name: `New Member Subscription - ${firstName} ${lastName}`,
description: `New member subscription for services: ${serviceNamesList} (${planDelay} month${planDelay > 1 ? 's' : ''})`, description: `New member subscription for services: ${serviceNamesList} (${planDelay} month${planDelay > 1 ? 's' : ''})`,
amount: totalAmount, amount: totalAmount,
addedAt: current_date_unix addedAt: subscription_date_unix
}); });
await incomeEntry.save(); await incomeEntry.save();
@ -409,6 +410,7 @@ export async function PUT(req:Request)
return payload.services as string[]; return payload.services as string[];
})(), })(),
planDelay : number = payload.planDelay ? payload.planDelay : 1 as number, planDelay : number = payload.planDelay ? payload.planDelay : 1 as number,
subscriptionDate : string | null = payload.subscriptionDate as string | null,
bodyState : { bodyState : {
currentBodyForm: String, currentBodyForm: String,
currentWeight: Number, currentWeight: Number,
@ -435,9 +437,9 @@ export async function PUT(req:Request)
const newServiceIds = newServices.map(id => new mongoose.Types.ObjectId(id as string)); const newServiceIds = newServices.map(id => new mongoose.Types.ObjectId(id as string));
const newServicesDocs = await serviceModel.find({ _id: { $in: newServiceIds } }); const newServicesDocs = await serviceModel.find({ _id: { $in: newServiceIds } });
// Current time variables // Current time variables - use custom date if provided, otherwise use current date
const current_date = new Date(); const current_date = subscriptionDate ? new Date(subscriptionDate) : new Date();
const current_date_unix = Math.floor(Date.now() / 1000); const current_date_unix = Math.floor(current_date.getTime() / 1000);
const planDelay_unix = planDelay * 2592000; const planDelay_unix = planDelay * 2592000;
// Process current services and new services // Process current services and new services
@ -476,13 +478,13 @@ export async function PUT(req:Request)
totalIncome += newServiceDoc.price * planDelay; totalIncome += newServiceDoc.price * planDelay;
incomeServiceNames.push(`${newServiceDoc.name} (extended)`); incomeServiceNames.push(`${newServiceDoc.name} (extended)`);
} else { } else {
// Replace expired service // Replace expired service - keep original registration date
const newExpiration = current_date_unix + planDelay_unix; const newExpiration = current_date_unix + planDelay_unix;
updatedServices[existingServiceIndex] = { updatedServices[existingServiceIndex] = {
serviceID: existingService.serviceID, serviceID: existingService.serviceID,
serviceName: existingService.serviceName, serviceName: existingService.serviceName,
registeredAt: current_date.toUTCString(), registeredAt: existingService.registeredAt,
registeredAt_unix: current_date_unix, registeredAt_unix: existingService.registeredAt_unix,
planDelay: planDelay, planDelay: planDelay,
planDelay_unix: planDelay_unix, planDelay_unix: planDelay_unix,
planExpAt: new Date(newExpiration * 1000).toUTCString(), planExpAt: new Date(newExpiration * 1000).toUTCString(),

View File

@ -51,6 +51,7 @@ export default function AddPopUp()
address: string | null, address: string | null,
services: string[], services: string[],
planDelay: string | null, planDelay: string | null,
subscriptionDate: string | null,
gendre: string | null, // m or w gendre: string | null, // m or w
startBodyForm: string | null, startBodyForm: string | null,
startWeight: string | null, startWeight: string | null,
@ -62,6 +63,7 @@ export default function AddPopUp()
address: '', address: '',
services: [], services: [],
planDelay: '', planDelay: '',
subscriptionDate: new Date().toISOString().split('T')[0], // Default to current date
gendre: 'm', gendre: 'm',
startBodyForm: '', startBodyForm: '',
startWeight: '', startWeight: '',
@ -336,6 +338,22 @@ export default function AddPopUp()
<div className="w-full flex lg:flex-row flex-col lg:gap-12 gap-7"> <div className="w-full flex lg:flex-row flex-col lg:gap-12 gap-7">
<div className="lg:w-1/2 w-full flex flex-col gap-5"> <div className="lg:w-1/2 w-full flex flex-col gap-5">
<h3 className="font-bold">{t('subscriptionInformations')}</h3> <h3 className="font-bold">{t('subscriptionInformations')}</h3>
<div className="flex flex-col">
<input
type="date"
id="subscriptionDate"
className="
disabled:bg-primary-dark/10
input lg:w-[350px] w-full border-2 border-primary-dark p-[11px]
rounded-md bg-primary dark:bg-primary-dark focus:outline-none
"
onChange={handleChange}
onBlur={handleBlur}
value={values?.subscriptionDate}
placeholder={t('subscriptionDate')}
/>
<p className="!text-error text-sm">{errors.subscriptionDate && touched.subscriptionDate && t(errors.subscriptionDate)}</p>
</div>
<div className="flex flex-col"> <div className="flex flex-col">
<input <input
type="number" type="number"
@ -465,6 +483,7 @@ export default function AddPopUp()
// this is the paper validation schema ( can`t go to next paper or submit if last paper if the validation schema return a false result ) // this is the paper validation schema ( can`t go to next paper or submit if last paper if the validation schema return a false result )
validationSchema: Yup.object().shape({ validationSchema: Yup.object().shape({
planDelay: Yup.number().typeError('mustBeANumber').required('thisFieldIsRequired'), planDelay: Yup.number().typeError('mustBeANumber').required('thisFieldIsRequired'),
subscriptionDate: Yup.date().required('thisFieldIsRequired'),
services: Yup.array().min(1 , "selectAtLeastOneService"), services: Yup.array().min(1 , "selectAtLeastOneService"),
startBodyForm: Yup.string().required('thisFieldIsRequired'), startBodyForm: Yup.string().required('thisFieldIsRequired'),
startWeight: Yup.number().typeError('mustBeANumber').required('thisFieldIsRequired'), startWeight: Yup.number().typeError('mustBeANumber').required('thisFieldIsRequired'),

View File

@ -268,7 +268,7 @@ export default function ServiceDetailsPopUp()
<p> <p>
{t('registerAt') + ' ' + '[ ' + {t('registerAt') + ' ' + '[ ' +
new Date(detailsPopUpData?.registerAt || '').toLocaleDateString( new Date(detailsPopUpData?.registerAt || '').toLocaleDateString(
t('locale') === 'ar' ? 'ar-EG' : 'en-US', t('locale') === 'ar' ? 'ar-EG' : 'en-GB',
{ {
weekday: 'long', weekday: 'long',
day: 'numeric', day: 'numeric',
@ -330,7 +330,7 @@ export default function ServiceDetailsPopUp()
</div> </div>
<div className="flex justify-between"> <div className="flex justify-between">
<span className="text-gray-600 dark:text-gray-400">{t('registeredAt')}:</span> <span className="text-gray-600 dark:text-gray-400">{t('registeredAt')}:</span>
<span>{new Date(service.registeredAt).toLocaleDateString()}</span> <span>{new Date(service.registeredAt).toLocaleDateString("en-GB")}</span>
</div> </div>
<div className="flex justify-between"> <div className="flex justify-between">
<span className="text-gray-600 dark:text-gray-400">{t('planDelay')}:</span> <span className="text-gray-600 dark:text-gray-400">{t('planDelay')}:</span>
@ -338,11 +338,11 @@ export default function ServiceDetailsPopUp()
</div> </div>
<div className="flex justify-between"> <div className="flex justify-between">
<span className="text-gray-600 dark:text-gray-400">{t('planExpAt')}:</span> <span className="text-gray-600 dark:text-gray-400">{t('planExpAt')}:</span>
<span>{new Date(service.planExpAt).toLocaleDateString()}</span> <span>{new Date(service.planExpAt).toLocaleDateString("en-GB")}</span>
</div> </div>
<div className="flex justify-between"> <div className="flex justify-between">
<span className="text-gray-600 dark:text-gray-400">{t('planUpdatedAt')}:</span> <span className="text-gray-600 dark:text-gray-400">{t('planUpdatedAt')}:</span>
<span>{new Date(service.planUpdatedAt).toLocaleDateString()}</span> <span>{new Date(service.planUpdatedAt).toLocaleDateString("en-GB")}</span>
</div> </div>
</div> </div>
</div> </div>

View File

@ -10,6 +10,7 @@ import useMediaQuery from '@mui/material/useMediaQuery';
import Slide from '@mui/material/Slide'; import Slide from '@mui/material/Slide';
import { TransitionProps } from '@mui/material/transitions'; import { TransitionProps } from '@mui/material/transitions';
import { Formik } from 'formik'; import { Formik } from 'formik';
import * as Yup from "yup";
import DialogContent from '@mui/material/DialogContent'; import DialogContent from '@mui/material/DialogContent';
import DialogContentText from '@mui/material/DialogContentText'; import DialogContentText from '@mui/material/DialogContentText';
import DialogActions from '@mui/material/DialogActions'; import DialogActions from '@mui/material/DialogActions';
@ -215,9 +216,18 @@ export default function UpdateSubPopUp()
//registerAt: updatePopUpData?.registerAt ? updatePopUpData?.registerAt : '', //registerAt: updatePopUpData?.registerAt ? updatePopUpData?.registerAt : '',
//registerAt_unix: updatePopUpData?.registerAt_unix ? updatePopUpData?.registerAt_unix : '', //registerAt_unix: updatePopUpData?.registerAt_unix ? updatePopUpData?.registerAt_unix : '',
planDelay: 0, planDelay: 0,
subscriptionDate: new Date().toISOString().split('T')[0], // Default to current date
//planDelay_unix: updatePopUpData?.planDelay_unix ? updatePopUpData?.planDelay_unix : 0, //planDelay_unix: updatePopUpData?.planDelay_unix ? updatePopUpData?.planDelay_unix : 0,
services: [], services: [],
}} }}
// Validation schema
validationSchema={Yup.object().shape({
planDelay: Yup.number().typeError('mustBeANumber').required('thisFieldIsRequired'),
subscriptionDate: Yup.date().required('thisFieldIsRequired'),
services: Yup.array().min(1, "selectAtLeastOneService"),
currentBodyForm: Yup.string().required('thisFieldIsRequired'),
currentWeight: Yup.number().typeError('mustBeANumber').required('thisFieldIsRequired'),
})}
// this function handle the submition of the formik form // this function handle the submition of the formik form
onSubmit={async (values, { setSubmitting }) => { onSubmit={async (values, { setSubmitting }) => {
// dispatch the update function // dispatch the update function
@ -321,9 +331,23 @@ export default function UpdateSubPopUp()
"> ">
<div className="w-full flex lg:flex-row flex-col lg:gap-12 gap-7"> <div className="w-full flex lg:flex-row flex-col lg:gap-12 gap-7">
<div className="lg:w-1/2 w-full flex flex-col gap-5"> <div className="lg:w-1/2 w-full flex flex-col gap-5">
<h3 className="font-bold">{t('planDetails')}</h3> <h3 className="font-bold">{t('subscriptionInformations')}</h3>
<div className="flex flex-col gap-5"> <div className="flex flex-col gap-5">
<input <input
type="date"
id="subscriptionDate"
className="
disabled:bg-primary-dark/10
input lg:w-[350px] w-full border-2 border-primary-dark p-[11px]
rounded-md bg-primary dark:bg-primary-dark focus:outline-none
"
onChange={handleChange}
onBlur={handleBlur}
value={values?.subscriptionDate}
placeholder={t('subscriptionDate')}
/>
<input
type="number"
id="planDelay" id="planDelay"
className=" className="
disabled:bg-primary-dark/10 disabled:bg-primary-dark/10

View File

@ -120,6 +120,7 @@
"memberAddText1": "اضافة عضو جديد للمجمع يمكنك من تتبع حالة العضو التسجيلية و الصحية", "memberAddText1": "اضافة عضو جديد للمجمع يمكنك من تتبع حالة العضو التسجيلية و الصحية",
"subscriptionInformations": "معلومات الاشتراك", "subscriptionInformations": "معلومات الاشتراك",
"planDelay": "مدة الخطة", "planDelay": "مدة الخطة",
"subscriptionDate": "تاريخ الاشتراك",
"healthInformations": "المعلومات الصحية", "healthInformations": "المعلومات الصحية",
"startWeight": "الوزن الابتدائي", "startWeight": "الوزن الابتدائي",
"bodyType": "حالة الجسم", "bodyType": "حالة الجسم",

View File

@ -121,6 +121,7 @@
"memberAddText1": "Adding a new member to the complex enables you to track the members registration and health status", "memberAddText1": "Adding a new member to the complex enables you to track the members registration and health status",
"subscriptionInformations": "Subscription informations", "subscriptionInformations": "Subscription informations",
"planDelay": "Plan delay", "planDelay": "Plan delay",
"subscriptionDate": "Subscription Date",
"healthInformations": "Health infomrations", "healthInformations": "Health infomrations",
"startWeight": "Start weight", "startWeight": "Start weight",
"bodyType": "Body state", "bodyType": "Body state",

View File

@ -237,6 +237,7 @@ const add = createAsyncThunk(
serviceName: string | null, serviceName: string | null,
}[] | null, }[] | null,
planDelay: string | null, planDelay: string | null,
subscriptionDate: string | null,
gendre: string | null, // m or w gendre: string | null, // m or w
bodyState: { bodyState: {
startBodyForm: string | null, startBodyForm: string | null,
@ -394,6 +395,7 @@ const updateSub = createAsyncThunk(
_id: string | null | undefined, _id: string | null | undefined,
services: string[] | undefined, services: string[] | undefined,
planDelay: number | null | undefined, planDelay: number | null | undefined,
subscriptionDate: string | null | undefined,
bodyState: { bodyState: {
currentBodyForm: string | null, currentBodyForm: string | null,
currentWeight: string | null currentWeight: string | null