Implement Subscription History and fix Interest Status Update flow
This commit is contained in:
1 parent
4ba4ce1e1b
commit
b3d33aca9c
42 files changed
+3950
-2677
No files matched your search
@@ -10,6 +10,7 @@ import {
|
||||
Button,
|
||||
Checkbox,
|
||||
ListItemText,
|
||||
TextField,
|
||||
} from "@mui/material";
|
||||
import { usePartnerPreferenceMasters } from "../hooks/useMasters";
|
||||
import { useCityMasters, useSubCasteMasters } from "../hooks/useDependentMasters";
|
||||
@@ -30,11 +31,30 @@ const PartnerPreferencesForm = ({
|
||||
const subCasteQuery = useSubCasteMasters(data.castes);
|
||||
const cityQuery = useCityMasters(data.states);
|
||||
|
||||
const ageRangeOptions = useMemo(() => {
|
||||
const ageOptions = useMemo(() => Array.from({ length: 53 }, (_, i) => i + 18), []);
|
||||
|
||||
const heightOptions = useMemo(() => {
|
||||
const raw = masters;
|
||||
if (!raw) return [];
|
||||
if (Array.isArray(raw)) return raw;
|
||||
return raw.ageRange || raw.age_range || [];
|
||||
return raw.heights || raw.height || [];
|
||||
}, [masters]);
|
||||
|
||||
const maritalStatusOptions = useMemo(() => {
|
||||
const raw = masters;
|
||||
if (!raw) return [];
|
||||
return raw.maritalStatus || raw.marital_status || [];
|
||||
}, [masters]);
|
||||
|
||||
const starOptions = useMemo(() => {
|
||||
const raw = masters;
|
||||
if (!raw) return [];
|
||||
return raw.stars || raw.star || [];
|
||||
}, [masters]);
|
||||
|
||||
const employeeTypeOptions = useMemo(() => {
|
||||
const raw = masters;
|
||||
if (!raw) return [];
|
||||
return raw.employeeTypes || raw.employee_type || [];
|
||||
}, [masters]);
|
||||
|
||||
const casteOptions = useMemo(() => {
|
||||
@@ -72,6 +92,8 @@ const PartnerPreferencesForm = ({
|
||||
return raw.annual_income || raw.annualIncome || [];
|
||||
}, [masters]);
|
||||
|
||||
const currencyOptions = useMemo(() => ["INR", "USD"], []);
|
||||
|
||||
const stateOptions = useMemo(() => {
|
||||
const raw = masters;
|
||||
if (!raw) return [];
|
||||
@@ -96,8 +118,15 @@ const PartnerPreferencesForm = ({
|
||||
const cityOptions = useMemo(() => {
|
||||
const raw = cityQuery.data;
|
||||
if (!raw) return [];
|
||||
if (Array.isArray(raw)) return raw;
|
||||
return raw.subCaste || raw.district || raw.data || [];
|
||||
if (Array.isArray(raw)) {
|
||||
const merged = raw.flatMap((entry) => {
|
||||
if (!entry) return [];
|
||||
if (Array.isArray(entry)) return entry;
|
||||
return entry.district || entry.districts || entry.data || [];
|
||||
});
|
||||
return merged;
|
||||
}
|
||||
return raw.district || raw.districts || raw.data || [];
|
||||
}, [cityQuery.data]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -107,12 +136,15 @@ const PartnerPreferencesForm = ({
|
||||
const handleChange = (field, value) => {
|
||||
const arrayFields = new Set([
|
||||
"castes",
|
||||
"subCastes",
|
||||
"sub_castes",
|
||||
"occupations",
|
||||
"educations",
|
||||
"hobbies",
|
||||
"states",
|
||||
"districts",
|
||||
"marital_statuses",
|
||||
"birth_stars",
|
||||
"employee_types",
|
||||
"currencies",
|
||||
]);
|
||||
const nextValue =
|
||||
arrayFields.has(field) && typeof value === "string"
|
||||
@@ -122,8 +154,8 @@ const PartnerPreferencesForm = ({
|
||||
const fieldsToClear = [field];
|
||||
|
||||
if (field === "castes") {
|
||||
updates.subCastes = [];
|
||||
fieldsToClear.push("subCastes");
|
||||
updates.sub_castes = [];
|
||||
fieldsToClear.push("sub_castes");
|
||||
}
|
||||
if (field === "states") {
|
||||
updates.districts = [];
|
||||
@@ -201,215 +233,297 @@ const PartnerPreferencesForm = ({
|
||||
<div className="w-full max-w-[1200px] mx-auto py-6 md:px-2 rounded-8">
|
||||
<form noValidate autoComplete="off" style={{ padding: 16 }}>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-20 gap-y-10 mb-6">
|
||||
{/* Age Range */}
|
||||
{/* 1. Age Range */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Age Range{requiredMark}
|
||||
</label>
|
||||
<FormControl
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
error={Boolean(errors.ageRange)}
|
||||
>
|
||||
<InputLabel id="ageRange-label">Select Age Range</InputLabel>
|
||||
<Select
|
||||
labelId="ageRange-label"
|
||||
label="Select Age Range"
|
||||
name="ageRange"
|
||||
value={data.ageRange}
|
||||
onChange={(e) => handleChange("ageRange", e.target.value)}
|
||||
inputRef={inputRef}
|
||||
disabled={isPartnerMastersLoading}
|
||||
sx={{
|
||||
"& .MuiSelect-select.Mui-disabled": {
|
||||
cursor: "not-allowed",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{ageRangeOptions.map((opt) => (
|
||||
<MenuItem key={opt.id ?? opt} value={opt.id ?? opt}>
|
||||
{opt.name || opt}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{errors.ageRange && (
|
||||
<p
|
||||
style={{
|
||||
color: "#d32f2f",
|
||||
margin: "3px 14px 0 14px",
|
||||
fontSize: "0.75rem",
|
||||
}}
|
||||
<label className="text-gray-900 text-[15px]">Age Range (From - To)</label>
|
||||
<div className="flex gap-2">
|
||||
<FormControl fullWidth variant="outlined" error={Boolean(errors.age_from)}>
|
||||
<InputLabel>From Age</InputLabel>
|
||||
<Select
|
||||
id="age_from"
|
||||
name="age_from"
|
||||
value={data.age_from}
|
||||
label="From Age"
|
||||
inputRef={inputRef}
|
||||
onChange={(e) => handleChange("age_from", e.target.value)}
|
||||
>
|
||||
{errors.ageRange}
|
||||
</p>
|
||||
)}
|
||||
</FormControl>
|
||||
{ageOptions.map((age) => (
|
||||
<MenuItem key={age} value={age}>{age}</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{errors.age_from && (
|
||||
<p style={{ color: "#d32f2f", margin: "3px 14px 0 14px", fontSize: "0.75rem" }}>
|
||||
{errors.age_from}
|
||||
</p>
|
||||
)}
|
||||
</FormControl>
|
||||
<FormControl fullWidth variant="outlined" error={Boolean(errors.age_to)}>
|
||||
<InputLabel>To Age</InputLabel>
|
||||
<Select
|
||||
id="age_to"
|
||||
name="age_to"
|
||||
value={data.age_to}
|
||||
label="To Age"
|
||||
onChange={(e) => handleChange("age_to", e.target.value)}
|
||||
>
|
||||
{ageOptions.map((age) => (
|
||||
<MenuItem key={age} value={age}>{age}</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{errors.age_to && (
|
||||
<p style={{ color: "#d32f2f", margin: "3px 14px 0 14px", fontSize: "0.75rem" }}>
|
||||
{errors.age_to}
|
||||
</p>
|
||||
)}
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Caste */}
|
||||
{/* 2. Height Range */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Caste{requiredMark}
|
||||
</label>
|
||||
<label className="text-gray-900 text-[15px]">Height Range (From - To)</label>
|
||||
<div className="flex gap-2">
|
||||
<FormControl fullWidth variant="outlined" error={Boolean(errors.height_from)}>
|
||||
<InputLabel>From Height</InputLabel>
|
||||
<Select
|
||||
id="height_from"
|
||||
name="height_from"
|
||||
value={data.height_from}
|
||||
label="From Height"
|
||||
onChange={(e) => handleChange("height_from", e.target.value)}
|
||||
>
|
||||
{heightOptions.map((h) => (
|
||||
<MenuItem key={h.id} value={h.id}>{h.height_text}</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{errors.height_from && (
|
||||
<p style={{ color: "#d32f2f", margin: "3px 14px 0 14px", fontSize: "0.75rem" }}>
|
||||
{errors.height_from}
|
||||
</p>
|
||||
)}
|
||||
</FormControl>
|
||||
<FormControl fullWidth variant="outlined" error={Boolean(errors.height_to)}>
|
||||
<InputLabel>To Height</InputLabel>
|
||||
<Select
|
||||
id="height_to"
|
||||
name="height_to"
|
||||
value={data.height_to}
|
||||
label="To Height"
|
||||
onChange={(e) => handleChange("height_to", e.target.value)}
|
||||
>
|
||||
{heightOptions.map((h) => (
|
||||
<MenuItem key={h.id} value={h.id}>{h.height_text}</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{errors.height_to && (
|
||||
<p style={{ color: "#d32f2f", margin: "3px 14px 0 14px", fontSize: "0.75rem" }}>
|
||||
{errors.height_to}
|
||||
</p>
|
||||
)}
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 3. Marital Status */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">Marital Status</label>
|
||||
{renderMultiSelect({
|
||||
name: "marital_statuses",
|
||||
label: "Marital Status",
|
||||
options: maritalStatusOptions,
|
||||
value: data.marital_statuses,
|
||||
getLabel: (opt) => opt.marital_status_name || opt.name,
|
||||
getValue: (opt) => opt.id,
|
||||
disabled: isPartnerMastersLoading,
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* 4. Birth Star */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">Birth Star</label>
|
||||
{renderMultiSelect({
|
||||
name: "birth_stars",
|
||||
label: "Birth Star",
|
||||
options: starOptions,
|
||||
value: data.birth_stars,
|
||||
getLabel: (opt) => opt.star_name || opt.name,
|
||||
getValue: (opt) => opt.id,
|
||||
disabled: isPartnerMastersLoading,
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* 5. Caste */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">Caste</label>
|
||||
{renderMultiSelect({
|
||||
name: "castes",
|
||||
label: "Caste",
|
||||
options: casteOptions,
|
||||
value: data.castes,
|
||||
getLabel: (opt) => opt.caste_name || opt.name || String(opt),
|
||||
getValue: (opt) => opt.id ?? opt,
|
||||
getLabel: (opt) => opt.caste_name || opt.name,
|
||||
getValue: (opt) => opt.id,
|
||||
disabled: isPartnerMastersLoading,
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Sub Caste */}
|
||||
{/* 6. Sub-Sect */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Sub Caste{requiredMark}
|
||||
</label>
|
||||
<label className="text-gray-900 text-[15px]">Sub-Sect</label>
|
||||
{renderMultiSelect({
|
||||
name: "subCastes",
|
||||
label: "Sub Caste",
|
||||
name: "sub_castes",
|
||||
label: "Sub-Sect",
|
||||
options: subCasteOptions,
|
||||
value: data.subCastes,
|
||||
getLabel: (opt) =>
|
||||
opt.sub_caste_name || opt.subCaste_name || opt.name || String(opt),
|
||||
getValue: (opt) => opt.id ?? opt,
|
||||
value: data.sub_castes,
|
||||
getLabel: (opt) => opt.sub_caste_name || opt.name,
|
||||
getValue: (opt) => opt.id,
|
||||
disabled: data.castes.length === 0 || subCasteQuery.isLoading,
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Occupation */}
|
||||
{/* 7. Qualification */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Occupation{requiredMark}
|
||||
</label>
|
||||
{renderMultiSelect({
|
||||
name: "occupations",
|
||||
label: "Occupation",
|
||||
options: occupationOptions,
|
||||
value: data.occupations,
|
||||
getLabel: (opt) => opt.occupation_name || opt.name || String(opt),
|
||||
getValue: (opt) => opt.id ?? opt,
|
||||
disabled: isPartnerMastersLoading,
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Qualification */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Qualification{requiredMark}
|
||||
</label>
|
||||
<label className="text-gray-900 text-[15px]">Qualification</label>
|
||||
{renderMultiSelect({
|
||||
name: "educations",
|
||||
label: "Qualification",
|
||||
options: educationOptions,
|
||||
value: data.educations,
|
||||
getLabel: (opt) => opt.education_name || opt.name || String(opt),
|
||||
getValue: (opt) => opt.id ?? opt,
|
||||
getLabel: (opt) => opt.education_name || opt.name,
|
||||
getValue: (opt) => opt.id,
|
||||
disabled: isPartnerMastersLoading,
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Lifestyle and Hobbies */}
|
||||
{/* 8. Occupation */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Lifestyle & Hobbies{requiredMark}
|
||||
</label>
|
||||
<label className="text-gray-900 text-[15px]">Occupation</label>
|
||||
{renderMultiSelect({
|
||||
name: "hobbies",
|
||||
label: "Lifestyle & Hobbies",
|
||||
options: hobbyOptions,
|
||||
value: data.hobbies,
|
||||
getLabel: (opt) => opt.hobby_name || opt.name || String(opt),
|
||||
getValue: (opt) => opt.id ?? opt,
|
||||
name: "occupations",
|
||||
label: "Occupation",
|
||||
options: occupationOptions,
|
||||
value: data.occupations,
|
||||
getLabel: (opt) => opt.occupation_name || opt.name,
|
||||
getValue: (opt) => opt.id,
|
||||
disabled: isPartnerMastersLoading,
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Annual Income */}
|
||||
{/* 9. Employee Type */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
Annual Income{requiredMark}
|
||||
</label>
|
||||
<FormControl
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
error={Boolean(errors.annualIncome)}
|
||||
>
|
||||
<InputLabel id="annualIncome-label">
|
||||
Select Annual Income
|
||||
</InputLabel>
|
||||
<Select
|
||||
labelId="annualIncome-label"
|
||||
label="Select Annual Income"
|
||||
name="annualIncome"
|
||||
value={data.annualIncome}
|
||||
onChange={(e) => handleChange("annualIncome", e.target.value)}
|
||||
disabled={isPartnerMastersLoading}
|
||||
sx={{
|
||||
"& .MuiSelect-select.Mui-disabled": {
|
||||
cursor: "not-allowed",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{annualIncomeOptions.map((opt) => (
|
||||
<MenuItem key={opt.id ?? opt} value={opt.id ?? opt}>
|
||||
{opt.annual_income_name || opt.name || opt}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{errors.annualIncome && (
|
||||
<p
|
||||
style={{
|
||||
color: "#d32f2f",
|
||||
margin: "3px 14px 0 14px",
|
||||
fontSize: "0.75rem",
|
||||
}}
|
||||
>
|
||||
{errors.annualIncome}
|
||||
</p>
|
||||
)}
|
||||
</FormControl>
|
||||
<label className="text-gray-900 text-[15px]">Employee Type</label>
|
||||
{renderMultiSelect({
|
||||
name: "employee_types",
|
||||
label: "Employee Type",
|
||||
options: employeeTypeOptions,
|
||||
value: data.employee_types,
|
||||
getLabel: (opt) => opt.employee_type_name || opt.name,
|
||||
getValue: (opt) => opt.id,
|
||||
disabled: isPartnerMastersLoading,
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* State */}
|
||||
{/* 10. Currency Type */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
State{requiredMark}
|
||||
</label>
|
||||
<label className="text-gray-900 text-[15px]">Income Currency Type</label>
|
||||
{renderMultiSelect({
|
||||
name: "currencies",
|
||||
label: "Currency",
|
||||
options: currencyOptions,
|
||||
value: data.currencies,
|
||||
getLabel: (opt) => opt,
|
||||
getValue: (opt) => opt,
|
||||
disabled: isPartnerMastersLoading,
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* 11. Income Range */}
|
||||
{data.currencies.includes("INR") && (
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">Annual Income (INR Range)</label>
|
||||
<div className="flex gap-2">
|
||||
<TextField
|
||||
id="inr_from"
|
||||
name="inr_from"
|
||||
fullWidth
|
||||
label="From (INR)"
|
||||
value={data.inr_from}
|
||||
error={Boolean(errors.inr_from)}
|
||||
helperText={errors.inr_from}
|
||||
onChange={(e) => handleChange("inr_from", e.target.value)}
|
||||
/>
|
||||
<TextField
|
||||
id="inr_to"
|
||||
name="inr_to"
|
||||
fullWidth
|
||||
label="To (INR)"
|
||||
value={data.inr_to}
|
||||
error={Boolean(errors.inr_to)}
|
||||
helperText={errors.inr_to}
|
||||
onChange={(e) => handleChange("inr_to", e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{data.currencies.includes("USD") && (
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">Annual Income (USD Range)</label>
|
||||
<div className="flex gap-2">
|
||||
<TextField
|
||||
id="usd_from"
|
||||
name="usd_from"
|
||||
fullWidth
|
||||
label="From (USD)"
|
||||
value={data.usd_from}
|
||||
error={Boolean(errors.usd_from)}
|
||||
helperText={errors.usd_from}
|
||||
onChange={(e) => handleChange("usd_from", e.target.value)}
|
||||
/>
|
||||
<TextField
|
||||
id="usd_to"
|
||||
name="usd_to"
|
||||
fullWidth
|
||||
label="To (USD)"
|
||||
value={data.usd_to}
|
||||
error={Boolean(errors.usd_to)}
|
||||
helperText={errors.usd_to}
|
||||
onChange={(e) => handleChange("usd_to", e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 12. State */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">State</label>
|
||||
{renderMultiSelect({
|
||||
name: "states",
|
||||
label: "State",
|
||||
options: stateOptions,
|
||||
value: data.states,
|
||||
getLabel: (opt) => opt.state_name || opt.name || String(opt),
|
||||
getValue: (opt) => opt.id ?? opt,
|
||||
getLabel: (opt) => opt.state_name || opt.name,
|
||||
getValue: (opt) => opt.id,
|
||||
disabled: isPartnerMastersLoading,
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* City */}
|
||||
{/* 13. City */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-gray-900 text-[15px]">
|
||||
City{requiredMark}
|
||||
</label>
|
||||
<label className="text-gray-900 text-[15px]">City</label>
|
||||
{renderMultiSelect({
|
||||
name: "districts",
|
||||
label: "City",
|
||||
options: cityOptions,
|
||||
value: data.districts,
|
||||
getLabel: (opt) =>
|
||||
opt.district_name || opt.city_name || opt.name || String(opt),
|
||||
getValue: (opt) => opt.id ?? opt,
|
||||
getLabel: (opt) => opt.district_name || opt.city_name || opt.name,
|
||||
getValue: (opt) => opt.id,
|
||||
disabled: data.states.length === 0 || cityQuery.isLoading,
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
size={12}
|
||||
style={{
|
||||
marginTop: 40,
|
||||
display: "flex",
|
||||
|
||||
Reference in new issue
Block a user