Untitled

 avatar
unknown
plain_text
12 days ago
19 kB
4
Indexable
import { FC, useState, useEffect } from "react";
import { useSelector } from "react-redux";
import { FaEdit } from "react-icons/fa";
import {
  Col,
  Row,
  Form,
  FormGroup,
  Label,
  Input,
  InputGroup,
  InputGroupText,
  Button,
} from "reactstrap";
import { RootState } from "@/Redux/Store";

interface LivingExpensesTabContentsProps {
  updateField: (field: string, value: any) => void;
}

const LivingExpensesTabContents: FC<LivingExpensesTabContentsProps> = ({
  updateField,
}) => {
  const budgetPlannerData = useSelector(
    (state: RootState) => state.budgetPlanner ?? {
      current_living_cost: {},
      post_living_cost: {},
      current_insurance: {},
      post_insurance: {},
    }
  );
  const [visibleNotes, setVisibleNotes] = useState<{ [key: string]: boolean }>(
    {}
  );
  const [currentValues, setCurrentValues] = useState<Record<string, string>>(
    {}
  );
  const [postValues, setPostValues] = useState<Record<string, string>>({});

  const livingCostFieldMappings = {
    Electricity: "electricity",
    Gas: "gas",
    Water: "water",
    "Landline/Mobile Phones": "landline_mobile_phone",
    "TV Licence": "tv_license",
    "Council Tax": "council_tax",
    "Ground Rent & Service Charges": "ground_rent_service_charges",
    "Buildings & Contents": "buildings_contents",
    "Mortgage Payment Protection": "mortgage_payment_protection",
    Endowment: "endowment",
    "Pension Contribution": "pension_contribution",
    Childcare: "childcare",
    Maintenance: "maintenance",
    Food: "food",
    "Car Maintenance": "car_maintenance",
    Fuel: "fuel",
    "Public Transport": "public_transport",
    "TV Broadband": "tv_broadband",
    "Recreation/Holidays": "recreation_holidays",
    Clothing: "clothing",
    "Medical Expenses": "medical_expenses",
    Education: "education",
    "Other Living Costs": "other_living_costs",
  };

  const insuranceFieldMappings = {
    "Motor Insurance": "motor_insurance",
    "Health Insurance": "health_insurance",
    "Payment Protection": "payment_protection",
    "Life Insurance": "life_insurance",
    "Dental Insurance": "dental_insurance",
    "Other Insurance": "other_insurance",
  };

  // Initialize local state with Redux data
  useEffect(() => {
    if (!budgetPlannerData) return;

    const initialCurrentValues: Record<string, string> = {};
    const initialPostValues: Record<string, string> = {};

    // Current Living Costs
    Object.entries(livingCostFieldMappings).forEach(([field, key]) => {
      const value =
        budgetPlannerData?.current_living_cost?.[
          key as keyof typeof budgetPlannerData.current_living_cost
        ] ?? 0;
      initialCurrentValues[
        `CurrentBudgetPlanner.${field.replace(/[\s/&]/g, "")}`
      ] = value !== 0 ? String(value) : "";
    });

    // Post Living Costs
    Object.entries(livingCostFieldMappings).forEach(([field, key]) => {
      const value =
        budgetPlannerData?.post_living_cost?.[
          key as keyof typeof budgetPlannerData.post_living_cost
        ] ?? 0;
      initialPostValues[
        `PostCompletionBudgetPlanner.${field.replace(/[\s/&]/g, "")}`
      ] = value !== 0 ? String(value) : "";
    });

    // Current Insurance
    Object.entries(insuranceFieldMappings).forEach(([field, key]) => {
      const value =
        budgetPlannerData?.current_insurance?.[
          key as keyof typeof budgetPlannerData.current_insurance
        ] ?? 0;
      initialCurrentValues[
        `CurrentBudgetPlanner.${field.replace(/[\s/&]/g, "")}`
      ] = value !== 0 ? String(value) : "";
    });

    // Post Insurance
    Object.entries(insuranceFieldMappings).forEach(([field, key]) => {
      const value =
        budgetPlannerData?.post_insurance?.[
          key as keyof typeof budgetPlannerData.post_insurance
        ] ?? 0;
      initialPostValues[
        `PostCompletionBudgetPlanner.${field.replace(/[\s/&]/g, "")}`
      ] = value !== 0 ? String(value) : "";
    });

    setCurrentValues((prev) => ({ ...prev, ...initialCurrentValues }));
    setPostValues((prev) => ({ ...prev, ...initialPostValues }));
  }, [budgetPlannerData]);

  // Update parent modal with current values
  useEffect(() => {
    const formatValues = (
      values: Record<string, string>,
      mappings: Record<string, string>,
      section: string
    ) => {
      const formatted = Object.entries(values)
        .filter(
          ([key]) =>
            key.startsWith("CurrentBudgetPlanner") && !key.includes("_Notes")
        )
        .reduce((acc, [key, value]) => {
          const fieldName = key.split(".")[1];
          const reduxFieldName = mappings[fieldName as keyof typeof mappings];
          if (reduxFieldName) {
            acc[reduxFieldName] = value === "" ? 0 : parseFloat(value);
          }
          return acc;
        }, {} as Record<string, number | 0>);
      formatted.total_living_expenses =
        parseFloat(
          calculateTotal(values, Object.keys(mappings), "CurrentBudgetPlanner")
        ) || 0;
      updateField(section, formatted);
    };

    formatValues(currentValues, livingCostFieldMappings, "current_living_cost");
    formatValues(currentValues, insuranceFieldMappings, "current_insurance");
  }, [currentValues, updateField]);

  // Update parent modal with post values
  useEffect(() => {
    const formatValues = (
      values: Record<string, string>,
      mappings: Record<string, string>,
      section: string
    ) => {
      const formatted = Object.entries(values)
        .filter(
          ([key]) =>
            key.startsWith("PostCompletionBudgetPlanner") &&
            !key.includes("_Notes")
        )
        .reduce((acc, [key, value]) => {
          const fieldName = key.split(".")[1];
          const reduxFieldName = mappings[fieldName as keyof typeof mappings];
          if (reduxFieldName) {
            acc[reduxFieldName] = value === "" ? 0 : parseFloat(value);
          }
          return acc;
        }, {} as Record<string, number | 0>);
      formatted.total_living_expenses =
        parseFloat(
          calculateTotal(
            values,
            Object.keys(mappings),
            "PostCompletionBudgetPlanner"
          )
        ) || 0;
      updateField(section, formatted);
    };

    formatValues(postValues, livingCostFieldMappings, "post_living_cost");
    formatValues(postValues, insuranceFieldMappings, "post_insurance");
  }, [postValues, updateField]);

  const toggleNotes = (event: React.MouseEvent, noteId: string) => {
    event.preventDefault();
    setVisibleNotes((prev) => ({ ...prev, [noteId]: !prev[noteId] }));
  };

  const renderFields = (
    prefix: string,
    fields: string[],
    mappings: Record<string, string>
  ) => (
    <Form>
      {fields.map((field) => {
        const id = field.replace(/[\s/&]/g, "");
        const fieldName = `${prefix}.${id}`;
        const reduxFieldName = mappings[field];
        return (
          <div key={id}>
            <FormGroup row className="mb-2">
              <Label
                for={`${prefix}_${reduxFieldName}`}
                sm={6}
                style={{ fontSize: "0.9rem" }}
              >
                {field}
              </Label>
              <Col sm={6}>
                <InputGroup>
                  <InputGroupText>£</InputGroupText>
                  <Input
                    type="number"
                    name={fieldName}
                    id={`${prefix}_${reduxFieldName}`}
                    className="numeric-decimal living-cost"
                    placeholder="0.00"
                    step="0.01"
                    value={
                      prefix === "CurrentBudgetPlanner"
                        ? currentValues[fieldName] || ""
                        : postValues[fieldName] || ""
                    }
                    onChange={(e) => {
                      const newValues =
                        prefix === "CurrentBudgetPlanner"
                          ? { ...currentValues, [fieldName]: e.target.value }
                          : { ...postValues, [fieldName]: e.target.value };
                      prefix === "CurrentBudgetPlanner"
                        ? setCurrentValues(newValues)
                        : setPostValues(newValues);
                    }}
                  />
                  <InputGroupText
                    className="penNoteIcon_Holder"
                    onClick={(e) =>
                      toggleNotes(
                        e,
                        `${
                          prefix === "CurrentBudgetPlanner" ? "" : "Post_"
                        }${reduxFieldName}_Notes`
                      )
                    }
                    style={{ cursor: "pointer" }}
                  >
                    <FaEdit />
                  </InputGroupText>
                </InputGroup>
              </Col>
            </FormGroup>
            <FormGroup
              className={`${reduxFieldName}_Notes_Holder mb-2`}
              style={{
                display: visibleNotes[
                  `${
                    prefix === "CurrentBudgetPlanner" ? "" : "Post_"
                  }${reduxFieldName}_Notes`
                ]
                  ? "block"
                  : "none",
              }}
            >
              <Label
                for={`${prefix}_${reduxFieldName}_Notes`}
                style={{ fontSize: "0.9rem" }}
              >
                Notes
              </Label>
              <Input
                type="textarea"
                name={`${prefix}.${reduxFieldName}_Notes`}
                id={`${prefix}_${reduxFieldName}_Notes`}
                className="textAreaRestrictions form-control"
                value={
                  prefix === "CurrentBudgetPlanner"
                    ? currentValues[`${prefix}.${reduxFieldName}_Notes`] || ""
                    : postValues[`${prefix}.${reduxFieldName}_Notes`] || ""
                }
                onChange={(e) => {
                  const newValues =
                    prefix === "CurrentBudgetPlanner"
                      ? {
                          ...currentValues,
                          [`${prefix}.${reduxFieldName}_Notes`]: e.target.value,
                        }
                      : {
                          ...postValues,
                          [`${prefix}.${reduxFieldName}_Notes`]: e.target.value,
                        };
                  prefix === "CurrentBudgetPlanner"
                    ? setCurrentValues(newValues)
                    : setPostValues(newValues);
                }}
              />
            </FormGroup>
          </div>
        );
      })}
    </Form>
  );

  const calculateTotal = (
    values: Record<string, string>,
    fields: string[],
    prefix: string
  ) => {
    return fields
      .reduce((sum, field) => {
        const fieldName = `${prefix}.${field.replace(/[\s/&]/g, "")}`;
        return sum + (parseFloat(values[fieldName]) || 0);
      }, 0)
      .toFixed(2);
  };

  const handleCopyFromCurrent = () => {
    const newPostValues: Record<string, string> = {};
    Object.keys(currentValues).forEach((key) => {
      const newKey = key.replace(
        "CurrentBudgetPlanner",
        "PostCompletionBudgetPlanner"
      );
      newPostValues[newKey] = currentValues[key];
    });
    setPostValues(newPostValues);
  };

  const renderSection = (
    title: string,
    prefix: string,
    fields?: string[],
    mappings?: Record<string, string>,
    isTotal?: boolean
  ) => (
    <div className="col-md-6">
      {!isTotal && <h4 className="text-center mb-3">{title}</h4>}
      <div
        className={`border rounded-3 shadow-sm ${
          isTotal ? "no-padding-vr no-border" : ""
        }`}
      >
        {!isTotal && (
          <div
            className={`bg-light border-bottom p-3 ${
              title === "Post Completion"
                ? "d-flex justify-content-between align-items-center"
                : ""
            }`}
          >
            <span className="fw-bold text-primary">
              {fields && Object.keys(insuranceFieldMappings).includes(fields[0])
                ? "Insurances"
                : "Living Costs"}
            </span>
            {title === "Post Completion" && (
              <Button color="primary" size="sm" onClick={handleCopyFromCurrent}>
                Copy from Current
              </Button>
            )}
          </div>
        )}
        <div className={`p-3 ${isTotal ? "no-padding-vr no-border" : ""}`}>
          {isTotal ? (
            <FormGroup row className="mb-2">
              <Label
                for={`${prefix}_TotalHome`}
                sm={6}
                style={{ fontSize: "0.9rem" }}
              >
                Total Living Expenses
              </Label>
              <Col sm={6}>
                <InputGroup>
                  <InputGroupText>£</InputGroupText>
                  <Input
                    type="number"
                    name={`${prefix}.TotalHome`}
                    id={`${prefix}_TotalHome`}
                    className="numeric-decimal fw-bold"
                    readOnly
                    placeholder="0.00"
                    step="0.01"
                    value={
                      prefix === "CurrentBudgetPlanner"
                        ? (
                            parseFloat(
                              calculateTotal(
                                currentValues,
                                Object.keys(livingCostFieldMappings),
                                prefix
                              )
                            ) +
                            parseFloat(
                              calculateTotal(
                                currentValues,
                                Object.keys(insuranceFieldMappings),
                                prefix
                              )
                            )
                          ).toFixed(2)
                        : (
                            parseFloat(
                              calculateTotal(
                                postValues,
                                Object.keys(livingCostFieldMappings),
                                prefix
                              )
                            ) +
                            parseFloat(
                              calculateTotal(
                                postValues,
                                Object.keys(insuranceFieldMappings),
                                prefix
                              )
                            )
                          ).toFixed(2)
                    }
                  />
                  <InputGroupText
                    className="penNoteIcon_Holder"
                    onClick={(e) =>
                      toggleNotes(
                        e,
                        `${
                          prefix === "CurrentBudgetPlanner" ? "" : "Post_"
                        }TotalHome_Notes`
                      )
                    }
                    style={{ cursor: "pointer" }}
                  >
                    <FaEdit />
                  </InputGroupText>
                </InputGroup>
              </Col>
            </FormGroup>
          ) : (
            renderFields(prefix, fields!, mappings!)
          )}
          {isTotal && (
            <FormGroup
              className="TotalHome_Notes_Holder mb-2"
              style={{
                display: visibleNotes[
                  `${
                    prefix === "CurrentBudgetPlanner" ? "" : "Post_"
                  }TotalHome_Notes`
                ]
                  ? "block"
                  : "none",
              }}
            >
              <Label
                for={`${prefix}_TotalHome_Notes`}
                style={{ fontSize: "0.9rem" }}
              >
                Notes
              </Label>
              <Input
                type="textarea"
                name={`${prefix}.TotalHome_Notes`}
                id={`${prefix}_TotalHome_Notes`}
                className="textAreaRestrictions form-control"
                value={
                  prefix === "CurrentBudgetPlanner"
                    ? currentValues[`${prefix}.TotalHome_Notes`] || ""
                    : postValues[`${prefix}.TotalHome_Notes`] || ""
                }
                onChange={(e) => {
                  const newValues =
                    prefix === "CurrentBudgetPlanner"
                      ? {
                          ...currentValues,
                          [`${prefix}.TotalHome_Notes`]: e.target.value,
                        }
                      : {
                          ...postValues,
                          [`${prefix}.TotalHome_Notes`]: e.target.value,
                        };
                  prefix === "CurrentBudgetPlanner"
                    ? setCurrentValues(newValues)
                    : setPostValues(newValues);
                }}
              />
            </FormGroup>
          )}
        </div>
      </div>
    </div>
  );

  return (
    <div>
      <p>
        <small>
          Please enter all monthly living costs accurately. Convert non-monthly
          expenses: multiply weekly by 4.3, divide quarterly by 3, annual by 12.
        </small>
      </p>
      <Row>
        {renderSection(
          "Current",
          "CurrentBudgetPlanner",
          Object.keys(livingCostFieldMappings),
          livingCostFieldMappings
        )}
        {renderSection(
          "Post Completion",
          "PostCompletionBudgetPlanner",
          Object.keys(livingCostFieldMappings),
          livingCostFieldMappings
        )}
      </Row>
      <Row className="mt-4">
        {renderSection(
          "Current",
          "CurrentBudgetPlanner",
          Object.keys(insuranceFieldMappings),
          insuranceFieldMappings
        )}
        {renderSection(
          "Post Completion",
          "PostCompletionBudgetPlanner",
          Object.keys(insuranceFieldMappings),
          insuranceFieldMappings
        )}
      </Row>
      <Row className="mt-4">
        {renderSection("", "CurrentBudgetPlanner", [], {}, true)}
        {renderSection("", "PostCompletionBudgetPlanner", [], {}, true)}
      </Row>
    </div>
  );
};

export default LivingExpensesTabContents;
Editor is loading...
Leave a Comment