Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/components/EmailTableModel/EmailTableModel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -385,11 +385,12 @@ function EmailTableModel({
}}
onOk={handleSubmit}
okText="Save"
bodyStyle={{ height: "70vh", overflowY: "auto" }}
>
{loading ? (
<FullScreenLoader />
) : (
<div style={{ height: "350px", overflowY: "auto" }}>
<div style={{ overflowY: "auto", marginBottom: 16 }}>
<div style={{ marginBottom: 16 }}>
<Row>
<Col span={12}>
Expand All @@ -399,6 +400,8 @@ function EmailTableModel({
style={{ width: "50%" }}
value={selectedTable}
onChange={(val) => setSelectedTable(val)}
showSearch={true}
allowClear={true}
>
{tableCatelog.map((table) => (
<Option key={table.table_name} value={table.table_name}>
Expand Down Expand Up @@ -534,6 +537,8 @@ function EmailTableModel({
val
)
}
showSearch={true}
allowClear={true}
>
{availableColumns.map((col) => (
<Option
Expand All @@ -558,6 +563,8 @@ function EmailTableModel({
val
)
}
showSearch={true}
allowClear={true}
>
{validateOperator.map((op) => (
<Option key={op} value={op}>
Expand Down Expand Up @@ -653,6 +660,8 @@ function EmailTableModel({
onChange={(val) =>
handleSortChange(val, index, "column")
}
showSearch={true}
allowClear={true}
>
{availableColumns.map((col) => (
<Option key={col.column_name} value={col.column_name}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ const BasicInformationForm: React.FC<BasicInformationFormProps> = ({
</DescriptionText>
<TwoColumnForm form={form} onValuesChange={handleFormValuesChange}>
<Row gutter={36}>
<Col span={10}>
<Col span={12}>
<StyledFormItem
required
label={
Expand Down Expand Up @@ -211,21 +211,40 @@ const BasicInformationForm: React.FC<BasicInformationFormProps> = ({
</StyledFormItem>
</Col>

<Col span={10}>
<Col span={12}>
<StyledFormItem
required
labelCol={{ span: 24 }}
wrapperCol={{ span: 24 }}
label={
<span>
Survey ID&nbsp;
<StyledTooltip title="It has to be a unique ID. Naming convention is survey name + round name. Ex: adp2.0_r1. It is used to name the prod tracker and dq tracker tables. Please limit the ID to 25 characters.">
<StyledTooltip title="It has to be a unique ID, alphanumeric with underscores. Naming convention is 'survey name + round name'. Ex: adp2.0_r1. It is used to name the prod tracker and dq tracker tables. Please limit the ID to 25 characters.">
<QuestionCircleOutlined />
</StyledTooltip>
</span>
}
name="survey_id"
style={{ display: "block" }}
rules={[
{
required: true,
message: "Please enter a survey ID",
},
{
pattern: /^[a-zA-Z0-9_]+$/,
message: (
<div style={{ maxWidth: "220px", whiteSpace: "normal" }}>
Survey ID can only contain letters, numbers, and
underscores
</div>
),
},
{
max: 25,
message: "Survey ID cannot exceed 25 characters",
},
Comment on lines +235 to +246
Copy link

Copilot AI Jul 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regex pattern for survey ID validation is well-implemented, restricting to alphanumeric characters and underscores only, which aligns with the tooltip description and prevents potential issues with special characters in database table names.

Suggested change
pattern: /^[a-zA-Z0-9_]+$/,
message: (
<div style={{ maxWidth: "220px", whiteSpace: "normal" }}>
Survey ID can only contain letters, numbers, and
underscores
</div>
),
},
{
max: 25,
message: "Survey ID cannot exceed 25 characters",
},
pattern: /^(?![_\.])[a-zA-Z0-9_.]{1,25}$/,
message: (
<div style={{ maxWidth: "220px", whiteSpace: "normal" }}>
Survey ID must start with a letter or number, can
contain letters, numbers, underscores, and periods,
and must not exceed 25 characters.
</div>
),
},

Copilot uses AI. Check for mistakes.
]}
>
<Input
id="basic-information-survey-id"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ function EnumeratorsHome() {
if (survey.payload.prime_geo_level_uid !== undefined) {
setPrimeGeoLevelUID(survey.payload.prime_geo_level_uid);
} else {
console.log("No prime_geo_level_uid found, setting to 0");
setPrimeGeoLevelUID(0);
}
};
Expand Down Expand Up @@ -140,7 +139,6 @@ function EnumeratorsHome() {
// Pre-filter fields
const fieldsToExclude = [
"status",
"custom_fields",
"enumerator_uid",
"monitor_locations",
"surveyor_locations",
Expand All @@ -150,10 +148,29 @@ function EnumeratorsHome() {

const filteredFields = Object.keys({ ...selectedRows[0] })
.filter((field) => !fieldsToExclude.includes(field))
.map((field) => ({
labelKey: field,
label: field,
}));
.flatMap((field) => {
if (field === "custom_fields") {
if (
selectedRows[0][field] &&
typeof selectedRows[0][field] === "object"
) {
const customFields = selectedRows[0][field];
return Object.keys(customFields)
.filter((key) => key !== "column_mapping")
.map((key) => ({
labelKey: key,
label: `custom_fields.${key}`,
}));
}
return [];
}
return [
{
labelKey: field,
label: field,
},
];
});

// Add location only if surveyor_locations exist
if (hasSurveyorLocations) {
Expand Down Expand Up @@ -230,7 +247,6 @@ function EnumeratorsHome() {

if (enumeratorRes.payload.status == 200) {
const originalData = enumeratorRes.payload.data.data;

// Handle empty data case immediately
if (!originalData || originalData.length == 0) {
setTableLoading(false); // Stop loading before navigation
Expand Down Expand Up @@ -657,25 +673,17 @@ function EnumeratorsHome() {

try {
// Only start loading when we're actually going to fetch data
if (!form_uid || !PrimeGeoLevelUID) {
if (!form_uid) {
await handleFormUID();
return;
}

// Only set loading and fetch data when we have all prerequisites
if (form_uid) {
if (!PrimeGeoLevelUID) {
const survey = await dispatch(
getSurveyBasicInformation({ survey_uid })
);
setPrimeGeoLevelUID(survey.payload.prime_geo_level_uid ?? 0);
return;
await fetchSurveyInfo();
}
}

// Only set loading and fetch data when we have all prerequisites
if (form_uid && PrimeGeoLevelUID) {
setTableLoading(true);
await getEnumeratorsList(form_uid);
return;
} else {
await handleFormUID();
return;
}
} catch (error) {
console.error("Error fetching data:", error);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from "../../../../redux/enumerators/enumeratorsActions";
import { useAppDispatch } from "../../../../redux/hooks";
import { CustomBtn, GlobalStyle } from "../../../../shared/Global.styled";
import { get } from "lodash";

interface IRowEditingModal {
data: DataItem[];
Expand All @@ -33,6 +34,7 @@ interface ConfigField {
bulk_editable: boolean;
column_name: string;
column_type: string;
allow_null_values: boolean;
}

function RowEditingModal({
Expand Down Expand Up @@ -74,6 +76,8 @@ function RowEditingModal({
);
const [hadSurveyorRole, setHadSurveyorRole] = useState(false);
const [originalStatus, setOriginalStatus] = useState<string>("");
const [nullableFields, setNullableFields] = useState<string[]>([]);
const [customFields, setCustomFields] = useState<string[]>([]);

const cancelHandler = () => {
onCancel();
Expand Down Expand Up @@ -106,6 +110,7 @@ function RowEditingModal({
}
if (originalData.length > 1 && form_uid) {
const { location, ...fieldsToUpdate } = updateData;

fieldsToUpdate.enumerator_type = Array.isArray(
fieldsToUpdate.enumerator_type
)
Expand Down Expand Up @@ -141,15 +146,11 @@ function RowEditingModal({
...originalData[indexToUpdate],
...updateData,
};

const { custom_fields, ...rest } = updatedRow;
const removedCustomFields: any = {};
for (const key in rest) {
if (key.startsWith("custom_fields.")) {
const fieldName = key.split("custom_fields.")[1];
removedCustomFields[fieldName] = rest[key];
delete rest[key];
}
for (const key in customFields) {
removedCustomFields[customFields[key]] = rest[customFields[key]];
delete rest[customFields[key]];
}

rest.custom_fields = {
Expand Down Expand Up @@ -261,9 +262,32 @@ function RowEditingModal({
.split(",")
.map((loc: string) => loc.trim());

const fetchEnumeratorColumnConfig = async (form_uid: string) => {
const configRes = await dispatch(
getEnumeratorsColumnConfig({ formUID: form_uid })
);
if (configRes.payload.status == 200) {
const configData = configRes.payload?.data?.data?.file_columns;
if (configData) {
const allow_null_fields = configData
.filter((field: ConfigField) => field.allow_null_values)
.map((field: ConfigField) => field.column_name);
if (!allow_null_fields.includes("home_address")) {
allow_null_fields.push("home_address");
}
setNullableFields(allow_null_fields);
}
}
return;
};

const setupFormData = () => {
const initialData: DataItem = {};

if (form_uid) {
fetchEnumeratorColumnConfig(form_uid);
}

let enumerator_type: string | string[] = "";
if (data[0].surveyor_status !== null && data[0].monitor_status !== null) {
enumerator_type = ["surveyor", "monitor"];
Expand All @@ -279,9 +303,15 @@ function RowEditingModal({
initialData.enumerator_type = enumerator_type;
initialData.enumerator_status = enumerator_status;

setCustomFields(
fields
.filter((field) => field.label.startsWith("custom_fields"))
.map((field) => field.labelKey)
);

fields.forEach((field) => {
if (field?.label?.startsWith("custom_fields")) {
initialData[field.label] =
initialData[field.labelKey] =
data[0]["custom_fields"][field.labelKey] || "";
} else if (field.labelKey === "location") {
initialData.location = locationList;
Expand Down Expand Up @@ -381,7 +411,9 @@ function RowEditingModal({
>
{updatedFields.map((field: Field, idx: number) => (
<Form.Item
required={field.labelKey !== "home_address"}
required={
nullableFields.includes(field.labelKey) ? false : true
}
key={idx}
name={field.labelKey}
initialValue={
Expand All @@ -406,7 +438,9 @@ function RowEditingModal({
}
rules={[
{
required: field.labelKey !== "home_address",
required: nullableFields.includes(field.labelKey)
? false
: true,
message: `Please enter ${field.labelKey
.split("_")
.map(
Expand Down
Loading