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

View File

@ -51,6 +51,7 @@ export default function AddPopUp()
address: string | null,
services: string[],
planDelay: string | null,
subscriptionDate: string | null,
gendre: string | null, // m or w
startBodyForm: string | null,
startWeight: string | null,
@ -62,6 +63,7 @@ export default function AddPopUp()
address: '',
services: [],
planDelay: '',
subscriptionDate: new Date().toISOString().split('T')[0], // Default to current date
gendre: 'm',
startBodyForm: '',
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="lg:w-1/2 w-full flex flex-col gap-5">
<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">
<input
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 )
validationSchema: Yup.object().shape({
planDelay: Yup.number().typeError('mustBeANumber').required('thisFieldIsRequired'),
subscriptionDate: Yup.date().required('thisFieldIsRequired'),
services: Yup.array().min(1 , "selectAtLeastOneService"),
startBodyForm: Yup.string().required('thisFieldIsRequired'),
startWeight: Yup.number().typeError('mustBeANumber').required('thisFieldIsRequired'),

View File

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

View File

@ -10,6 +10,7 @@ import useMediaQuery from '@mui/material/useMediaQuery';
import Slide from '@mui/material/Slide';
import { TransitionProps } from '@mui/material/transitions';
import { Formik } from 'formik';
import * as Yup from "yup";
import DialogContent from '@mui/material/DialogContent';
import DialogContentText from '@mui/material/DialogContentText';
import DialogActions from '@mui/material/DialogActions';
@ -215,9 +216,18 @@ export default function UpdateSubPopUp()
//registerAt: updatePopUpData?.registerAt ? updatePopUpData?.registerAt : '',
//registerAt_unix: updatePopUpData?.registerAt_unix ? updatePopUpData?.registerAt_unix : '',
planDelay: 0,
subscriptionDate: new Date().toISOString().split('T')[0], // Default to current date
//planDelay_unix: updatePopUpData?.planDelay_unix ? updatePopUpData?.planDelay_unix : 0,
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
onSubmit={async (values, { setSubmitting }) => {
// 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="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">
<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"
className="
disabled:bg-primary-dark/10

View File

@ -120,6 +120,7 @@
"memberAddText1": "اضافة عضو جديد للمجمع يمكنك من تتبع حالة العضو التسجيلية و الصحية",
"subscriptionInformations": "معلومات الاشتراك",
"planDelay": "مدة الخطة",
"subscriptionDate": "تاريخ الاشتراك",
"healthInformations": "المعلومات الصحية",
"startWeight": "الوزن الابتدائي",
"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",
"subscriptionInformations": "Subscription informations",
"planDelay": "Plan delay",
"subscriptionDate": "Subscription Date",
"healthInformations": "Health infomrations",
"startWeight": "Start weight",
"bodyType": "Body state",

View File

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