You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

2073 lines
138 KiB

  1. import {
  2. Button,
  3. FormControlLabel,
  4. Grid, InputAdornment, Switch, TextField, Typography,
  5. Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, Select, MenuItem, IconButton
  6. } from '@mui/material';
  7. import MainCard from "../../../components/MainCard";
  8. import * as React from "react";
  9. import {useForm} from "react-hook-form";
  10. import {useContext, useEffect, useState} from "react";
  11. import LoadingComponent from "../../extra-pages/LoadingComponent";
  12. import {useLocation, useNavigate, useParams} from "react-router-dom";
  13. import {
  14. GeneralConfirmWindow,
  15. getComboValueByIdList,
  16. getComboValueByLabel,
  17. getDateString,
  18. getDeletedRecordWithRefList,
  19. getIdList,
  20. getNewRecordWithRefList, isOptionEqualToValue, isStringEmptyAfterTrim, notifyDeleteError, notifyDeleteSuccess,
  21. notifySaveSuccess, trimDataBeforePost,
  22. } from "../../../utils/CommonFunction";
  23. import Autocomplete from "@mui/material/Autocomplete";
  24. import axios from "axios";
  25. import {apiPath} from "../../../auth/utils";
  26. import {
  27. CHECK_EVENT_DUPLICATE,
  28. GET_CLIENT_PATH,
  29. GET_CONSULTANT_COMBO_LIST,
  30. GET_SUB_DIVISION_COMBO_LIST,
  31. POST_CLIENT_PATH
  32. } from "../../../utils/ApiPathConst";
  33. import {LIONER_BUTTON_THEME, LIONER_LONG_BUTTON_THEME, GENERAL_RED_COLOR} from "../../../themes/colorConst";
  34. import {eventFrequencyCombo, EVENT_REGION_COMBO, EVENT_TYPE_COMBO} from "../../../utils/ComboConst";
  35. import {DatePicker} from "@mui/x-date-pickers/DatePicker";
  36. import dayjs from "dayjs";
  37. import {DemoItem} from "@mui/x-date-pickers/internals/demo";
  38. import {AdapterDayjs} from "@mui/x-date-pickers/AdapterDayjs";
  39. import {LocalizationProvider} from "@mui/x-date-pickers/LocalizationProvider";
  40. import {ThemeProvider} from "@emotion/react";
  41. import UploadContext from "../../../components/UploadProvider";
  42. import {isObjEmpty} from "../../../utils/Utils";
  43. import AbilityContext from "../../../components/AbilityProvider";
  44. import {CARD_MAX_WIDTH} from "../../../themes/themeConst";
  45. const ClientForm = ({ refClientDetail, isNewRecord, getClientDetail }) => {
  46. const location = useLocation();
  47. const queryParams = new URLSearchParams(location.search);
  48. const refId = queryParams.get("refId");
  49. const params = useParams();
  50. const navigate = useNavigate();
  51. const ability = useContext(AbilityContext);
  52. const [onReady, setOnReady] = useState(false);
  53. const [errors, setErrors] = useState({});
  54. const [clientDetail, setClientDetail] = useState({});
  55. const [isCollectData, setIsCollectData] = useState(false);
  56. const [userConfirm, setUserConfirm] = useState(false);
  57. const [isEditing, setIsEditing] = useState(false);
  58. const { setIsUploading } = useContext(UploadContext);
  59. const [refClient, setRefClient] = useState({});
  60. const [consultantComboList, setConsultantComboList] = useState([]);
  61. const [selectedConsultant, setSelectedConsultant] = useState(null);
  62. const [isFirstInit, setIsFirstInit] = useState(true);
  63. // Form data
  64. const { register, getValues, setValue } = useForm();
  65. const [dob, setDob] = useState(null);
  66. const [dobError, setDobError] = React.useState(null);
  67. // Handler to navigate back
  68. const returnSearchPage = () => {
  69. navigate('/client');
  70. }
  71. const FIXED_HEADER_HEIGHT = 120; // <-- **IMPORTANT: Set this to the height of your actual fixed header in pixels**
  72. const handleFocus = (event) => {
  73. setTimeout(() => {
  74. const element = event.target;
  75. // Get the element's position relative to the viewport
  76. const rect = element.getBoundingClientRect();
  77. // Calculate the target scroll position (Current scroll position + element top position - Header height)
  78. const targetScrollY = window.scrollY + rect.top - FIXED_HEADER_HEIGHT;
  79. // Scroll the window to the new position
  80. window.scrollTo({
  81. top: targetScrollY,
  82. behavior: 'smooth'
  83. });
  84. // Ensure the element has focus
  85. element.focus();
  86. }, 100);
  87. };
  88. // Handler to enable edit mode
  89. const handleEditClick = () => {
  90. setIsEditing(true);
  91. };
  92. useEffect(() => {
  93. if (!isObjEmpty(refClient) && consultantComboList.length > 0 && isFirstInit) {
  94. const matched = consultantComboList.find(c => c.id === refClient.consultantId);
  95. setSelectedConsultant(matched || null);
  96. setValue("consultantId", matched || null);
  97. setIsFirstInit(false);
  98. }
  99. }, [refClient, consultantComboList, isFirstInit]);
  100. // 1. Earned Income
  101. const [earnedIncome, setEarnedIncome] = useState({
  102. salaryCurrent: '',
  103. salaryLast: '',
  104. bonusCurrent: '',
  105. bonusLast: '',
  106. otherEarnedCurrent: '',
  107. otherEarnedLast: ''
  108. });
  109. const handleEarnedIncomeChange = (field, value) => {
  110. setEarnedIncome(prev => ({ ...prev, [field]: value }));
  111. };
  112. const totalEarnedCurrent = (parseFloat(earnedIncome.salaryCurrent) || 0) +
  113. (parseFloat(earnedIncome.bonusCurrent) || 0) +
  114. (parseFloat(earnedIncome.otherEarnedCurrent) || 0);
  115. const totalEarnedLast = (parseFloat(earnedIncome.salaryLast) || 0) +
  116. (parseFloat(earnedIncome.bonusLast) || 0) +
  117. (parseFloat(earnedIncome.otherEarnedLast) || 0);
  118. // 2. Unearned Income (Updated for Current Year / Last Year columns as per Image 2)
  119. const [unearnedIncome, setUnearnedIncome] = useState({
  120. companyInterestCurrent: '',
  121. companyInterestLast: '',
  122. dividendsCurrent: '',
  123. dividendsLast: '',
  124. rentalsCurrent: '',
  125. rentalsLast: '',
  126. investmentIncomeCurrent: '',
  127. investmentIncomeLast: '',
  128. otherUnearnedCurrent: '',
  129. otherUnearnedLast: ''
  130. });
  131. const handleUnearnedIncomeChange = (field, value) => {
  132. setUnearnedIncome(prev => ({ ...prev, [field]: value }));
  133. };
  134. const totalUnearnedCurrent = (parseFloat(unearnedIncome.companyInterestCurrent) || 0) +
  135. (parseFloat(unearnedIncome.dividendsCurrent) || 0) +
  136. (parseFloat(unearnedIncome.rentalsCurrent) || 0) +
  137. (parseFloat(unearnedIncome.investmentIncomeCurrent) || 0) +
  138. (parseFloat(unearnedIncome.otherUnearnedCurrent) || 0);
  139. const totalUnearnedLast = (parseFloat(unearnedIncome.companyInterestLast) || 0) +
  140. (parseFloat(unearnedIncome.dividendsLast) || 0) +
  141. (parseFloat(unearnedIncome.rentalsLast) || 0) +
  142. (parseFloat(unearnedIncome.investmentIncomeLast) || 0) +
  143. (parseFloat(unearnedIncome.otherUnearnedLast) || 0);
  144. // Total Income Calculation
  145. const totalIncomeCurrent = totalEarnedCurrent + totalUnearnedCurrent;
  146. const totalIncomeLast = totalEarnedLast + totalUnearnedLast;
  147. // 3. Expenditure Statement
  148. const [expenditure, setExpenditure] = useState({
  149. mortgageCurrent: '',
  150. mortgageLast: '',
  151. rentCurrent: '',
  152. rentLast: '',
  153. schoolingCurrent: '',
  154. schoolingLast: '',
  155. membershipsCurrent: '',
  156. membershipsLast: '',
  157. otherExpenditureCurrent: '',
  158. otherExpenditureLast: '',
  159. interestCurrent: '',
  160. interestLast: '',
  161. principalCurrent: '',
  162. principalLast: '',
  163. otherPrefFinanceCurrent: '',
  164. otherPrefFinanceLast: ''
  165. });
  166. const handleExpenditureChange = (field, value) => {
  167. setExpenditure(prev => ({ ...prev, [field]: value }));
  168. };
  169. const totalExpenditureCurrent = (parseFloat(expenditure.mortgageCurrent) || 0) +
  170. (parseFloat(expenditure.rentCurrent) || 0) +
  171. (parseFloat(expenditure.schoolingCurrent) || 0) +
  172. (parseFloat(expenditure.membershipsCurrent) || 0) +
  173. (parseFloat(expenditure.otherExpenditureCurrent) || 0) +
  174. (parseFloat(expenditure.interestCurrent) || 0) +
  175. (parseFloat(expenditure.principalCurrent) || 0)+
  176. (parseFloat(expenditure.otherPrefFinanceCurrent) || 0);
  177. const totalExpenditureLast = (parseFloat(expenditure.mortgageLast) || 0) +
  178. (parseFloat(expenditure.rentLast) || 0) +
  179. (parseFloat(expenditure.schoolingLast) || 0) +
  180. (parseFloat(expenditure.membershipsLast) || 0) +
  181. (parseFloat(expenditure.otherExpenditureLast) || 0) +
  182. (parseFloat(expenditure.interestLast) || 0) +
  183. (parseFloat(expenditure.principalLast) || 0)+
  184. (parseFloat(expenditure.otherPrefFinanceLast) || 0);
  185. // 4. Liquid & Non-Liquid Assets (Combined for Image 4)
  186. const [assets, setAssets] = useState({
  187. // Liquid Assets
  188. cashDepositsCurrent: '',
  189. cashDepositsLast: '',
  190. investmentsCurrent: '',
  191. investmentsLast: '',
  192. otherLiquidCurrent: '',
  193. otherLiquidLast: '',
  194. // Non-Liquid Assets
  195. netBusinessInterestCurrent: '',
  196. netBusinessInterestLast: '',
  197. personalPropertiesCurrent: '',
  198. personalPropertiesLast: '',
  199. realEstateCurrent: '',
  200. realEstateLast: '',
  201. otherNonLiquidCurrent: '',
  202. otherNonLiquidLast: ''
  203. });
  204. const handleAssetsChange = (field, value) => {
  205. setAssets(prev => ({ ...prev, [field]: value }));
  206. };
  207. const totalLiquidAssetCurrent = (parseFloat(assets.cashDepositsCurrent) || 0) +
  208. (parseFloat(assets.investmentsCurrent) || 0) +
  209. (parseFloat(assets.otherLiquidCurrent) || 0);
  210. const totalLiquidAssetLast = (parseFloat(assets.cashDepositsLast) || 0) +
  211. (parseFloat(assets.investmentsLast) || 0) +
  212. (parseFloat(assets.otherLiquidLast) || 0);
  213. const totalNonLiquidAssetCurrent = (parseFloat(assets.netBusinessInterestCurrent) || 0) +
  214. (parseFloat(assets.personalPropertiesCurrent) || 0) +
  215. (parseFloat(assets.realEstateCurrent) || 0) + // ← NEW
  216. (parseFloat(assets.otherNonLiquidCurrent) || 0);
  217. const totalNonLiquidAssetLast = (parseFloat(assets.netBusinessInterestLast) || 0) +
  218. (parseFloat(assets.personalPropertiesLast) || 0) +
  219. (parseFloat(assets.realEstateLast) || 0) + // ← NEW
  220. (parseFloat(assets.otherNonLiquidLast) || 0);
  221. const totalAssetsCurrent = totalLiquidAssetCurrent + totalNonLiquidAssetCurrent;
  222. const totalAssetsLast = totalLiquidAssetLast + totalNonLiquidAssetLast;
  223. // 5. Liabilities (Combined with Existing Premium Financing/Policy Loan section from Image 5)
  224. const [liabilities, setLiabilities] = useState({
  225. personalLoansCurrent: '',
  226. personalLoansLast: '',
  227. mortgagesCurrent: '',
  228. mortgagesLast: '',
  229. marginAccountCurrent: '',
  230. marginAccountLast: '',
  231. loanGuaranteesCurrent: '',
  232. loanGuaranteesLast: '',
  233. bankingFacilityCurrent: '',
  234. bankingFacilityLast: '',
  235. // Existing Premium Financing/Policy Loan (Principal and Other from Image 5)
  236. prefFinancePrincipalCurrent: '',
  237. prefFinancePrincipalLast: '',
  238. prefFinanceOtherCurrent: '',
  239. prefFinanceOtherLast: '',
  240. });
  241. const handleLiabilitiesChange = (field, value) => {
  242. setLiabilities(prev => ({ ...prev, [field]: value }));
  243. };
  244. const totalLiabilitiesCurrent = (parseFloat(liabilities.personalLoansCurrent) || 0) +
  245. (parseFloat(liabilities.mortgagesCurrent) || 0) +
  246. (parseFloat(liabilities.marginAccountCurrent) || 0) +
  247. (parseFloat(liabilities.loanGuaranteesCurrent) || 0) +
  248. (parseFloat(liabilities.bankingFacilityCurrent) || 0) +
  249. (parseFloat(liabilities.prefFinancePrincipalCurrent) || 0) +
  250. (parseFloat(liabilities.prefFinanceOtherCurrent) || 0);
  251. const totalLiabilitiesLast = (parseFloat(liabilities.personalLoansLast) || 0) +
  252. (parseFloat(liabilities.mortgagesLast) || 0) +
  253. (parseFloat(liabilities.marginAccountLast) || 0) +
  254. (parseFloat(liabilities.loanGuaranteesLast) || 0) +
  255. (parseFloat(liabilities.bankingFacilityLast) || 0) +
  256. (parseFloat(liabilities.prefFinancePrincipalLast) || 0) +
  257. (parseFloat(liabilities.prefFinanceOtherLast) || 0);
  258. const dobErrorMessage = React.useMemo(() => {
  259. switch (dobError) {
  260. case 'invalidDate': {
  261. return "Invalid date";
  262. }
  263. }
  264. }, [dobError]);
  265. // DELETE WINDOW RELATED
  266. const [isWindowOpen, setIsWindowOpen] = React.useState(false);
  267. const handleClose = () => {
  268. setIsWindowOpen(false);
  269. };
  270. const handleDeleteClick = () => {
  271. setIsWindowOpen(true);
  272. };
  273. const copyClientAsNew = () => {
  274. navigate(`/event/maintain/-1?refId=${params.id}`);
  275. };
  276. const formatNumberForDisplay = (num) => {
  277. console.log(num);
  278. // 1. Handle null, undefined, or empty string input gracefully (return as is)
  279. if (num === null || num === undefined || num === '') return '';
  280. // Convert to a string and use regex to allow up to one decimal point and digits
  281. const numString = String(num);
  282. // Check if the input ends with a decimal point (e.g., '100.')
  283. // We preserve this during display so the user can continue typing decimals.
  284. const endsWithDecimal = numString.endsWith('.');
  285. // Attempt to parse the number
  286. const numericValue = parseFloat(numString);
  287. // 2. If it's NaN (like if the input was only '.'), return the original string
  288. if (isNaN(numericValue) && numString !== '.') return numString;
  289. // 3. Use Intl.NumberFormat to add commas
  290. const formatted = new Intl.NumberFormat('en-US', {
  291. minimumFractionDigits: 0,
  292. maximumFractionDigits: 2,
  293. }).format(numericValue);
  294. // 4. If the original string ended with a decimal (e.g., '123.'),
  295. // re-append the decimal point because Intl.NumberFormat removes it for whole numbers.
  296. if (endsWithDecimal) {
  297. // If the formatted number doesn't already contain a decimal point
  298. if (!formatted.includes('.')) {
  299. return formatted + '.';
  300. }
  301. }
  302. console.log(formatted);
  303. return formatted;
  304. };
  305. // Function to clean the string input back to a raw number string for state storage
  306. const cleanNumberForState = (inputString) => {
  307. if (inputString === null || inputString === undefined) return '';
  308. // 1. Remove commas (,) and any thousand separators
  309. let cleanedString = inputString.toString().replace(/,/g, '');
  310. // 2. Check for multiple decimal points (only keep the first one)
  311. const parts = cleanedString.split('.');
  312. if (parts.length > 2) {
  313. // If there are multiple decimals, we revert to the state before the last one was typed
  314. // This prevents '123.45.' from breaking the number
  315. return parts[0] + '.' + parts.slice(1).join('');
  316. }
  317. // 3. Optional: Remove characters that are NOT digits or a decimal point
  318. // cleanedString = cleanedString.replace(/[^0-9.]/g, '');
  319. // Return the cleaned string. We keep it as a STRING to preserve leading zeros
  320. // and prevent immediate number conversion issues.
  321. return cleanedString;
  322. };
  323. function updateData() {
  324. axios.delete(`${apiPath}${GET_CLIENT_PATH}/${params.id}`)
  325. .then((response) => {
  326. if (response.status === 204) {
  327. notifyDeleteSuccess();
  328. setIsWindowOpen(false);
  329. returnSearchPage();
  330. }
  331. })
  332. .catch(error => {
  333. console.log(error);
  334. return false;
  335. });
  336. }
  337. function getConsultantCombo() {
  338. axios.get(`${apiPath}${GET_CONSULTANT_COMBO_LIST}`, {
  339. params: {}
  340. })
  341. .then((response) => {
  342. if (response.status === 200) {
  343. setConsultantComboList(response.data.records);
  344. }
  345. })
  346. .catch(error => {
  347. console.log(error);
  348. return false;
  349. });
  350. }
  351. useEffect(() => {
  352. if (!isNewRecord) {
  353. setRefClient(refClientDetail);
  354. }
  355. getConsultantCombo();
  356. }, []);
  357. useEffect(() => {
  358. if (!isObjEmpty(refClient)) {
  359. setValue("lastname", refClient.lastname);
  360. setValue("firstname", refClient.firstname);
  361. setValue("email", refClient.email);
  362. setValue("phone1", refClient.phone1);
  363. setValue("phone1Code", refClient.phone1Code);
  364. setValue("phone2", refClient.phone2);
  365. setValue("remarks", refClient.remarks);
  366. setValue("caseManagerId", 1);
  367. setValue("crAddressRoom", refClient.crAddressRoom);
  368. setValue("crAddressFloor", refClient.crAddressFloor);
  369. setValue("crAddressBuilding", refClient.crAddressBuilding);
  370. setValue("crAddressStreet", refClient.crAddressStreet);
  371. setValue("crAddressStreet", refClient.crAddressStreet);
  372. setValue("crAddressArea", refClient.crAddressArea);
  373. setValue("crAddressCity", refClient.crAddressCity);
  374. setValue("crAddressCountry", refClient.crAddressCountry);
  375. setValue("crAddressPostalCode", refClient.crAddressPostalCode);
  376. setValue("corAddressRoom", refClient.corAddressRoom);
  377. setValue("corAddressFloor", refClient.corAddressFloor);
  378. setValue("corAddressBlock", refClient.corAddressBlock);
  379. setValue("corAddressBuilding", refClient.corAddressBuilding);
  380. setValue("corAddressStreet", refClient.corAddressStreet);
  381. setValue("corAddressArea", refClient.corAddressArea);
  382. setValue("corAddressCity", refClient.corAddressCity);
  383. setValue("corAddressCountry", refClient.corAddressCountry);
  384. setValue("corAddressPostalCode", refClient.corAddressPostalCode);
  385. earnedIncome.salaryCurrent = refClient.salaryCurrent;
  386. earnedIncome.salaryLast = refClient.salaryLast;
  387. earnedIncome.bonusCurrent = refClient.bonusCurrent;
  388. earnedIncome.bonusLast = refClient.bonusLast;
  389. earnedIncome.otherEarnedCurrent = refClient.otherEarnedCurrent;
  390. earnedIncome.otherEarnedLast = refClient.otherEarnedLast;
  391. unearnedIncome.companyInterestCurrent = refClient.companyInterestCurrent;
  392. unearnedIncome.companyInterestLast = refClient.companyInterestLast;
  393. unearnedIncome.dividendsCurrent = refClient.dividendsCurrent;
  394. unearnedIncome.dividendsLast = refClient.dividendsLast;
  395. unearnedIncome.rentalsCurrent = refClient.rentalsCurrent;
  396. unearnedIncome.rentalsLast = refClient.rentalsLast;
  397. unearnedIncome.investmentIncomeCurrent = refClient.investmentIncomeCurrent;
  398. unearnedIncome.investmentIncomeLast = refClient.investmentIncomeLast;
  399. unearnedIncome.otherUnearnedCurrent = refClient.otherUnearnedCurrent;
  400. unearnedIncome.otherUnearnedLast = refClient.otherUnearnedLast;
  401. expenditure.mortgageCurrent = refClient.mortgageCurrent;
  402. expenditure.mortgageLast = refClient.mortgageLast;
  403. expenditure.rentCurrent = refClient.rentCurrent;
  404. expenditure.rentLast = refClient.rentLast;
  405. expenditure.schoolingCurrent = refClient.schoolingCurrent;
  406. expenditure.schoolingLast = refClient.schoolingLast;
  407. expenditure.membershipsCurrent = refClient.membershipsCurrent;
  408. expenditure.membershipsLast = refClient.membershipsLast;
  409. expenditure.otherExpenditureCurrent = refClient.otherExpenditureCurrent;
  410. expenditure.otherExpenditureLast = refClient.otherExpenditureLast;
  411. expenditure.interestCurrent = refClient.interestCurrent;
  412. expenditure.interestLast = refClient.interestLast;
  413. expenditure.principalCurrent = refClient.principalCurrent;
  414. expenditure.principalLast = refClient.principalLast;
  415. expenditure.otherPrefFinanceCurrent = refClient.otherPrefFinanceCurrent;
  416. expenditure.otherPrefFinanceLast = refClient.otherPrefFinanceLast;
  417. assets.cashDepositsCurrent = refClient.cashDepositsCurrent;
  418. assets.cashDepositsLast = refClient.cashDepositsLast;
  419. assets.investmentsCurrent = refClient.investmentsCurrent;
  420. assets.investmentsLast = refClient.investmentsLast;
  421. assets.otherLiquidCurrent = refClient.otherLiquidCurrent;
  422. assets.otherLiquidLast = refClient.otherLiquidLast;
  423. assets.netBusinessInterestCurrent = refClient.netBusinessInterestCurrent;
  424. assets.netBusinessInterestLast = refClient.netBusinessInterestLast;
  425. assets.personalPropertiesCurrent = refClient.personalPropertiesCurrent;
  426. assets.personalPropertiesLast = refClient.personalPropertiesLast;
  427. assets.realEstateCurrent = refClient.realEstateCurrent;
  428. assets.realEstateLast = refClient.realEstateLast;
  429. assets.otherNonLiquidCurrent = refClient.otherNonLiquidCurrent;
  430. assets.otherNonLiquidLast = refClient.otherNonLiquidLast;
  431. liabilities.personalLoansCurrent = refClient.personalLoansCurrent;
  432. liabilities.personalLoansLast = refClient.personalLoansLast;
  433. liabilities.mortgagesCurrent = refClient.mortgagesCurrent;
  434. liabilities.mortgagesLast = refClient.mortgagesLast;
  435. liabilities.marginAccountCurrent = refClient.marginAccountCurrent;
  436. liabilities.marginAccountLast = refClient.marginAccountLast;
  437. liabilities.loanGuaranteesCurrent = refClient.loanGuaranteesCurrent;
  438. liabilities.loanGuaranteesLast = refClient.loanGuaranteesLast;
  439. liabilities.bankingFacilityCurrent = refClient.bankingFacilityCurrent;
  440. liabilities.bankingFacilityLast = refClient.bankingFacilityLast;
  441. liabilities.prefFinancePrincipalCurrent = refClient.prefFinancePrincipalCurrent;
  442. liabilities.prefFinancePrincipalLast = refClient.prefFinancePrincipalLast;
  443. liabilities.prefFinanceOtherCurrent = refClient.prefFinanceOtherCurrent;
  444. liabilities.prefFinanceOtherLast = refClient.prefFinanceOtherLast;
  445. //totalEarnedCurrent = refClient.totalEarnedCurrent;
  446. //totalEarnedLast = refClient.totalEarnedLast;
  447. // Set consultantId for Autocomplete
  448. const selectedConsultant = consultantComboList.find(
  449. (option) => option.id === refClient.consultantId
  450. );
  451. setValue("consultantId", selectedConsultant || null);
  452. setDob(dayjs(getDateString(refClient.dob)));
  453. }
  454. }, [refClient, consultantComboList]);
  455. useEffect(() => {
  456. if (!isObjEmpty(refClient)) {
  457. setOnReady(true);
  458. } else if (isNewRecord) {
  459. setOnReady(true);
  460. setIsEditing(true);
  461. }
  462. }, [refClient]);
  463. useEffect(() => {
  464. if (isCollectData) {
  465. const values = getValues();
  466. const formErrors = {};
  467. if (isStringEmptyAfterTrim(values.lastname)) {
  468. formErrors.lastname = 'Last Name is required';
  469. }
  470. setErrors(formErrors);
  471. if (Object.keys(formErrors).length === 0) {
  472. let data = {};
  473. data["id"] = isNewRecord ? params.id : refClientDetail.id;
  474. data["lastname"] = values.lastname;
  475. data["firstname"] = values.firstname;
  476. data["email"] = values.email;
  477. data["phone1"] = values.phone1;
  478. data["phone1Code"] = values.phone1Code;
  479. data["phone2"] = values.phone2;
  480. data["remarks"] = values.remarks;
  481. data["caseManagerId"] = 1;
  482. data["consultantId"] = values.consultantId ? values.consultantId.id : null;
  483. data["dob"] = dob === null ? null : dayjs(dob).format('YYYY-MM-DD');
  484. data["crAddressRoom"] = values.crAddressRoom;
  485. data["crAddressFloor"] = values.crAddressFloor;
  486. data["crAddressBlock"] = values.crAddressBlock;
  487. data["crAddressBuilding"] = values.crAddressBuilding;
  488. data["crAddressStreet"] = values.crAddressStreet;
  489. data["crAddressArea"] = values.crAddressArea;
  490. data["crAddressCity"] = values.crAddressCity;
  491. data["crAddressCountry"] = values.crAddressCountry;
  492. data["crAddressPostalCode"] = values.crAddressPostalCode;
  493. data["corAddressRoom"] = values.corAddressRoom;
  494. data["corAddressFloor"] = values.corAddressFloor;
  495. data["corAddressBlock"] = values.corAddressBlock;
  496. data["corAddressBuilding"] = values.corAddressBuilding;
  497. data["corAddressStreet"] = values.corAddressStreet;
  498. data["corAddressArea"] = values.corAddressArea;
  499. data["corAddressCity"] = values.corAddressCity;
  500. data["corAddressCountry"] = values.corAddressCountry;
  501. data["corAddressPostalCode"] = values.corAddressPostalCode;
  502. data = {
  503. ...data, // Keep all existing header fields
  504. ...earnedIncome,
  505. ...unearnedIncome,
  506. ...expenditure,
  507. ...assets,
  508. ...liabilities,
  509. totalEarnedCurrent,
  510. totalEarnedLast,
  511. totalUnearnedCurrent,
  512. totalUnearnedLast,
  513. totalAssetsCurrent,
  514. totalAssetsLast,
  515. totalIncomeCurrent,
  516. totalIncomeLast,
  517. totalExpenditureCurrent,
  518. totalExpenditureLast,
  519. totalLiquidAssetCurrent,
  520. totalLiquidAssetLast,
  521. totalNonLiquidAssetCurrent,
  522. totalNonLiquidAssetLast,
  523. totalLiabilitiesCurrent,
  524. totalLiabilitiesLast,
  525. };
  526. setClientDetail(data);
  527. } else if (isCollectData) {
  528. setUserConfirm(false);
  529. setIsCollectData(false);
  530. }
  531. }
  532. }, [isCollectData]);
  533. useEffect(() => {
  534. if (userConfirm) {
  535. postClient();
  536. }
  537. setUserConfirm(false);
  538. }, [clientDetail]);
  539. const submitData = () => {
  540. setIsCollectData(!isCollectData);
  541. setUserConfirm(true);
  542. };
  543. const updateIsEdit = () => {
  544. setIsEditing(!isEditing);
  545. };
  546. function postClient() {
  547. setIsUploading(true);
  548. const temp = trimDataBeforePost(clientDetail);
  549. axios.post(`${apiPath}${POST_CLIENT_PATH}`, temp)
  550. .then((response) => {
  551. if (response.status === 200) {
  552. notifySaveSuccess();
  553. if (isNewRecord) {
  554. setIsUploading(false);
  555. navigate('/client');
  556. } else {
  557. setIsUploading(false);
  558. getClientDetail(params.id);
  559. setIsEditing(!isEditing);
  560. }
  561. setIsCollectData(!isCollectData);
  562. }
  563. })
  564. .catch(error => {
  565. if (error.response.status === 422) {
  566. const formErrors = {};
  567. formErrors.subDivision = error.response.data.error;
  568. setErrors(formErrors);
  569. }
  570. console.log(error);
  571. setIsUploading(false);
  572. return false;
  573. });
  574. }
  575. return (
  576. !onReady ?
  577. <LoadingComponent />
  578. :
  579. <MainCard content={false} sx={{ width: CARD_MAX_WIDTH }}>
  580. <Typography variant="h5" sx={{ mt: 3, ml: 3, mb: 1 }}>
  581. Information
  582. </Typography>
  583. <form>
  584. <Grid container>
  585. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ mt: 1, ml: 3, mr: 3, mb: 3 }}>
  586. <Grid container alignItems={"flex-start"}>
  587. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, mt: 1, display: 'flex', alignItems: 'flex-start' }}>
  588. <Typography variant="lionerSize" component="span">
  589. Client Code: <Typography sx={{ color: GENERAL_RED_COLOR }} component="span">*</Typography>
  590. </Typography>
  591. </Grid>
  592. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  593. <TextField
  594. fullWidth
  595. {...register("clientCode", { value: refClient.clientCode })}
  596. id='clientCode'
  597. required
  598. inputProps={{ maxLength: 255, style: { fontSize: '1.1rem' } }}
  599. InputProps={{ style: { minHeight: '42.5px', maxHeight: '50vh' } }}
  600. multiline
  601. maxRows={3}
  602. error={!!errors.lastname}
  603. helperText={errors.lastname}
  604. disabled
  605. autoComplete="off"
  606. />
  607. </Grid>
  608. </Grid>
  609. </Grid>
  610. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ mt: 1, ml: 3, mr: 3, mb: 3 }}>
  611. <Grid container alignItems={"flex-start"}>
  612. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, mt: 1, display: 'flex', alignItems: 'flex-start' }}>
  613. <Typography variant="lionerSize" component="span">
  614. Last Name(Surname/Family Name): <Typography sx={{ color: GENERAL_RED_COLOR }} component="span">*</Typography>
  615. </Typography>
  616. </Grid>
  617. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  618. <TextField
  619. fullWidth
  620. {...register("lastname", { value: refClient.lastname })}
  621. id='lastname'
  622. required
  623. inputProps={{ maxLength: 255, style: { fontSize: '1.1rem' } }}
  624. InputProps={{ style: { minHeight: '42.5px', maxHeight: '50vh' } }}
  625. multiline
  626. maxRows={3}
  627. error={!!errors.lastname}
  628. helperText={errors.lastname}
  629. disabled={!isEditing}
  630. autoComplete="off"
  631. />
  632. </Grid>
  633. </Grid>
  634. </Grid>
  635. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ mt: 1, ml: 3, mr: 3, mb: 3 }}>
  636. <Grid container alignItems={"flex-start"}>
  637. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, mt: 1, display: 'flex', alignItems: 'flex-start' }}>
  638. <Typography variant="lionerSize" component="span">
  639. First Name(Given Name/Forename):
  640. </Typography>
  641. </Grid>
  642. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  643. <TextField
  644. fullWidth
  645. {...register("firstname", { value: refClient.firstname })}
  646. id='firstname'
  647. required
  648. inputProps={{ maxLength: 255, style: { fontSize: '1.1rem' } }}
  649. InputProps={{ style: { minHeight: '42.5px', maxHeight: '50vh' } }}
  650. multiline
  651. maxRows={3}
  652. disabled={!isEditing}
  653. autoComplete="off"
  654. />
  655. </Grid>
  656. </Grid>
  657. </Grid>
  658. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  659. <Grid container alignItems={"center"}>
  660. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  661. <Typography variant="lionerSize" component="span">
  662. Date of Birth:
  663. </Typography>
  664. </Grid>
  665. <Grid item xs={7} sm={7} md={7} lg={7}>
  666. <LocalizationProvider dateAdapter={AdapterDayjs}>
  667. <DemoItem components={['DatePicker']}>
  668. <DatePicker
  669. id="dob"
  670. size="small"
  671. required
  672. value={dob === null ? null : dayjs(dob)}
  673. onChange={(newValue) => setDob(newValue)}
  674. format="DD/MM/YYYY"
  675. onError={(newError) => setDobError(newError)}
  676. slotProps={{
  677. field: { clearable: true },
  678. textField: {
  679. error: !!errors.dob || dobError,
  680. helperText: dobError ? dobErrorMessage : errors.dob,
  681. },
  682. }}
  683. disabled={!isEditing}
  684. />
  685. </DemoItem>
  686. </LocalizationProvider>
  687. </Grid>
  688. </Grid>
  689. </Grid>
  690. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  691. <Grid container alignItems={"center"}>
  692. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  693. <Typography variant="lionerSize" component="span">
  694. Email Address:
  695. </Typography>
  696. </Grid>
  697. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  698. <TextField
  699. fullWidth
  700. inputProps={{ maxLength: 50 }}
  701. size="small"
  702. {...register("email", { value: refClient.email })}
  703. id='email'
  704. disabled={!isEditing}
  705. autoComplete="off"
  706. />
  707. </Grid>
  708. </Grid>
  709. </Grid>
  710. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  711. <Grid container alignItems={"center"}>
  712. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  713. <Typography variant="lionerSize" component="span">
  714. Phone Number:
  715. </Typography>
  716. </Grid>
  717. <Grid item xs={1} sm={1} md={1} lg={1.5}>
  718. <TextField
  719. fullWidth
  720. inputProps={{ maxLength: 5 }}
  721. size="small"
  722. {...register("phone1Code", { value: refClient.phote1Code })}
  723. id='phone1Code'
  724. disabled={!isEditing}
  725. autoComplete="off"
  726. />
  727. </Grid>
  728. <Grid item xs={0.1} sm={0.1} md={0.1} lg={0.15}>
  729. </Grid>
  730. <Grid item xs={6} sm={6} md={6} lg={5}>
  731. <TextField
  732. fullWidth
  733. inputProps={{ maxLength: 20 }}
  734. size="small"
  735. {...register("phone1", { value: refClient.phone1 })}
  736. id='phone1'
  737. disabled={!isEditing}
  738. autoComplete="off"
  739. />
  740. </Grid>
  741. </Grid>
  742. </Grid>
  743. {/*
  744. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  745. <Grid container alignItems={"flex-start"}>
  746. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  747. <Typography variant="lionerSize" component="span">
  748. Case Manager: <Typography sx={{ color: GENERAL_RED_COLOR }} component="span"></Typography>
  749. </Typography>
  750. </Grid>
  751. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  752. <TextField
  753. fullWidth
  754. inputProps={{ maxLength: 50 }}
  755. size="small"
  756. {...register("cm", { value: "N/A" })}
  757. id='cm'
  758. disabled
  759. autoComplete="off"
  760. />
  761. </Grid>
  762. </Grid>
  763. </Grid>
  764. */}
  765. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}></Grid>
  766. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  767. <Grid container alignItems={"flex-start"}>
  768. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  769. <Typography variant="lionerSize" component="span">
  770. Consultant: <Typography sx={{ color: GENERAL_RED_COLOR }} component="span"></Typography>
  771. </Typography>
  772. </Grid>
  773. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  774. <Autocomplete
  775. disablePortal
  776. id="consultant-combo-box"
  777. options={consultantComboList}
  778. getOptionLabel={(option) => option.name || ""}
  779. isOptionEqualToValue={(option, value) => option.id === value.id}
  780. value={selectedConsultant}
  781. onChange={(e, v) => {
  782. setSelectedConsultant(v);
  783. setValue('consultantId', v); }
  784. }
  785. renderInput={(params) => (
  786. <TextField
  787. {...params}
  788. label="Consultant"
  789. name="consultant"
  790. />
  791. )}
  792. disabled={!isEditing}
  793. />
  794. </Grid>
  795. </Grid>
  796. </Grid>
  797. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  798. <Grid container alignItems={"center"}>
  799. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  800. <Typography variant="lionerSize" component="span">
  801. Rs. Address(Room):
  802. </Typography>
  803. </Grid>
  804. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  805. <TextField
  806. fullWidth
  807. inputProps={{ maxLength: 50 }}
  808. size="small"
  809. {...register("crAddressRoom", { value: refClient.crAddressRoom })}
  810. id='crAddressRoom'
  811. disabled={!isEditing}
  812. autoComplete="off"
  813. />
  814. </Grid>
  815. </Grid>
  816. </Grid>
  817. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  818. <Grid container alignItems={"center"}>
  819. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  820. <Typography variant="lionerSize" component="span">
  821. Rs. Address(Floor):
  822. </Typography>
  823. </Grid>
  824. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  825. <TextField
  826. fullWidth
  827. inputProps={{ maxLength: 50 }}
  828. size="small"
  829. {...register("crAddressFloor", { value: refClient.crAddressFloor })}
  830. id='crAddressFloor'
  831. disabled={!isEditing}
  832. autoComplete="off"
  833. />
  834. </Grid>
  835. </Grid>
  836. </Grid>
  837. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  838. <Grid container alignItems={"center"}>
  839. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  840. <Typography variant="lionerSize" component="span">
  841. Rs. Address(Block):
  842. </Typography>
  843. </Grid>
  844. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  845. <TextField
  846. fullWidth
  847. inputProps={{ maxLength: 50 }}
  848. size="small"
  849. {...register("crAddressBlock", { value: refClient.crAddressBlock })}
  850. id='crAddressBlock'
  851. disabled={!isEditing}
  852. autoComplete="off"
  853. />
  854. </Grid>
  855. </Grid>
  856. </Grid>
  857. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  858. <Grid container alignItems={"center"}>
  859. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  860. <Typography variant="lionerSize" component="span">
  861. Rs. Address(Buliding):
  862. </Typography>
  863. </Grid>
  864. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  865. <TextField
  866. fullWidth
  867. inputProps={{ maxLength: 50 }}
  868. size="small"
  869. {...register("crAddressBuilding", { value: refClient.crAddressBuilding })}
  870. id='crAddressBuilding'
  871. disabled={!isEditing}
  872. autoComplete="off"
  873. />
  874. </Grid>
  875. </Grid>
  876. </Grid>
  877. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  878. <Grid container alignItems={"center"}>
  879. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  880. <Typography variant="lionerSize" component="span">
  881. Rs. Address(Street):
  882. </Typography>
  883. </Grid>
  884. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  885. <TextField
  886. fullWidth
  887. inputProps={{ maxLength: 50 }}
  888. size="small"
  889. {...register("crAddressStreet", { value: refClient.crAddressStreet })}
  890. id='crAddressStreet'
  891. disabled={!isEditing}
  892. autoComplete="off"
  893. />
  894. </Grid>
  895. </Grid>
  896. </Grid>
  897. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  898. <Grid container alignItems={"center"}>
  899. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  900. <Typography variant="lionerSize" component="span">
  901. Rs. Address(Area):
  902. </Typography>
  903. </Grid>
  904. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  905. <TextField
  906. fullWidth
  907. inputProps={{ maxLength: 50 }}
  908. size="small"
  909. {...register("crAddressArea", { value: refClient.crAddressArea })}
  910. id='crAddressArea'
  911. disabled={!isEditing}
  912. autoComplete="off"
  913. />
  914. </Grid>
  915. </Grid>
  916. </Grid>
  917. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  918. <Grid container alignItems={"center"}>
  919. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  920. <Typography variant="lionerSize" component="span">
  921. Rs. Address(City):
  922. </Typography>
  923. </Grid>
  924. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  925. <TextField
  926. fullWidth
  927. inputProps={{ maxLength: 50 }}
  928. size="small"
  929. {...register("crAddressCity", { value: refClient.crAddressCity })}
  930. id='crAddressCity'
  931. disabled={!isEditing}
  932. autoComplete="off"
  933. />
  934. </Grid>
  935. </Grid>
  936. </Grid>
  937. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  938. <Grid container alignItems={"center"}>
  939. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  940. <Typography variant="lionerSize" component="span">
  941. Rs. Address(Country):
  942. </Typography>
  943. </Grid>
  944. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  945. <TextField
  946. fullWidth
  947. inputProps={{ maxLength: 50 }}
  948. size="small"
  949. {...register("crAddressCountry", { value: refClient.crAddressCountry })}
  950. id='crAddressCountry'
  951. disabled={!isEditing}
  952. autoComplete="off"
  953. />
  954. </Grid>
  955. </Grid>
  956. </Grid>
  957. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  958. <Grid container alignItems={"center"}>
  959. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  960. <Typography variant="lionerSize" component="span">
  961. Rs. Address(Postal Code):
  962. </Typography>
  963. </Grid>
  964. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  965. <TextField
  966. fullWidth
  967. inputProps={{ maxLength: 50 }}
  968. size="small"
  969. {...register("crAddressPostalCode", { value: refClient.crAddressPostalCode })}
  970. id='crAddressPostalCode'
  971. disabled={!isEditing}
  972. autoComplete="off"
  973. />
  974. </Grid>
  975. </Grid>
  976. </Grid>
  977. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  978. </Grid>
  979. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  980. <Grid container alignItems={"center"}>
  981. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  982. <Typography variant="lionerSize" component="span">
  983. Corr. Address(Room):
  984. </Typography>
  985. </Grid>
  986. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  987. <TextField
  988. fullWidth
  989. inputProps={{ maxLength: 50 }}
  990. size="small"
  991. {...register("corAddressRoom", { value: refClient.corAddressRoom })}
  992. id='corAddressRoom'
  993. disabled={!isEditing}
  994. autoComplete="off"
  995. />
  996. </Grid>
  997. </Grid>
  998. </Grid>
  999. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  1000. <Grid container alignItems={"center"}>
  1001. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  1002. <Typography variant="lionerSize" component="span">
  1003. Corr. Address(Floor):
  1004. </Typography>
  1005. </Grid>
  1006. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  1007. <TextField
  1008. fullWidth
  1009. inputProps={{ maxLength: 50 }}
  1010. size="small"
  1011. {...register("corAddressFloor", { value: refClient.corAddressFloor })}
  1012. id='corAddressFloor'
  1013. disabled={!isEditing}
  1014. autoComplete="off"
  1015. />
  1016. </Grid>
  1017. </Grid>
  1018. </Grid>
  1019. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  1020. <Grid container alignItems={"center"}>
  1021. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  1022. <Typography variant="lionerSize" component="span">
  1023. Corr. Address(Block):
  1024. </Typography>
  1025. </Grid>
  1026. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  1027. <TextField
  1028. fullWidth
  1029. inputProps={{ maxLength: 50 }}
  1030. size="small"
  1031. {...register("corAddressBlock", { value: refClient.corAddressBlock })}
  1032. id='corAddressBlock'
  1033. disabled={!isEditing}
  1034. autoComplete="off"
  1035. />
  1036. </Grid>
  1037. </Grid>
  1038. </Grid>
  1039. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  1040. <Grid container alignItems={"center"}>
  1041. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  1042. <Typography variant="lionerSize" component="span">
  1043. Corr. Address(Buliding):
  1044. </Typography>
  1045. </Grid>
  1046. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  1047. <TextField
  1048. fullWidth
  1049. inputProps={{ maxLength: 50 }}
  1050. size="small"
  1051. {...register("corAddressBuilding", { value: refClient.corAddressBuilding })}
  1052. id='corAddressBuilding'
  1053. disabled={!isEditing}
  1054. autoComplete="off"
  1055. />
  1056. </Grid>
  1057. </Grid>
  1058. </Grid>
  1059. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  1060. <Grid container alignItems={"center"}>
  1061. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  1062. <Typography variant="lionerSize" component="span">
  1063. Corr. Address(Street):
  1064. </Typography>
  1065. </Grid>
  1066. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  1067. <TextField
  1068. fullWidth
  1069. inputProps={{ maxLength: 50 }}
  1070. size="small"
  1071. {...register("corAddressStreet", { value: refClient.corAddressStreet })}
  1072. id='corAddressStreet'
  1073. disabled={!isEditing}
  1074. autoComplete="off"
  1075. />
  1076. </Grid>
  1077. </Grid>
  1078. </Grid>
  1079. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  1080. <Grid container alignItems={"center"}>
  1081. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  1082. <Typography variant="lionerSize" component="span">
  1083. Corr. Address(Area):
  1084. </Typography>
  1085. </Grid>
  1086. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  1087. <TextField
  1088. fullWidth
  1089. inputProps={{ maxLength: 50 }}
  1090. size="small"
  1091. {...register("corAddressArea", { value: refClient.corAddressArea })}
  1092. id='corAddressArea'
  1093. disabled={!isEditing}
  1094. autoComplete="off"
  1095. />
  1096. </Grid>
  1097. </Grid>
  1098. </Grid>
  1099. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  1100. <Grid container alignItems={"center"}>
  1101. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  1102. <Typography variant="lionerSize" component="span">
  1103. Corr. Address(City):
  1104. </Typography>
  1105. </Grid>
  1106. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  1107. <TextField
  1108. fullWidth
  1109. inputProps={{ maxLength: 50 }}
  1110. size="small"
  1111. {...register("corAddressCity", { value: refClient.corAddressCity })}
  1112. id='corAddressCity'
  1113. disabled={!isEditing}
  1114. autoComplete="off"
  1115. />
  1116. </Grid>
  1117. </Grid>
  1118. </Grid>
  1119. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  1120. <Grid container alignItems={"center"}>
  1121. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  1122. <Typography variant="lionerSize" component="span">
  1123. Corr. Address(Country):
  1124. </Typography>
  1125. </Grid>
  1126. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  1127. <TextField
  1128. fullWidth
  1129. inputProps={{ maxLength: 50 }}
  1130. size="small"
  1131. {...register("corAddressCountry", { value: refClient.corAddressCountry })}
  1132. id='corAddressCountry'
  1133. disabled={!isEditing}
  1134. autoComplete="off"
  1135. />
  1136. </Grid>
  1137. </Grid>
  1138. </Grid>
  1139. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  1140. <Grid container alignItems={"center"}>
  1141. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  1142. <Typography variant="lionerSize" component="span">
  1143. Corr. Address(Postal Code):
  1144. </Typography>
  1145. </Grid>
  1146. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  1147. <TextField
  1148. fullWidth
  1149. inputProps={{ maxLength: 50 }}
  1150. size="small"
  1151. {...register("corAddressPostalCode", { value: refClient.corAddressPostalCode })}
  1152. id='corAddressPostalCode'
  1153. disabled={!isEditing}
  1154. autoComplete="off"
  1155. />
  1156. </Grid>
  1157. </Grid>
  1158. </Grid>
  1159. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  1160. </Grid>
  1161. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3, mt: 1 }}>
  1162. <Grid container alignItems={"flex-start"}>
  1163. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, mt: 1, display: 'flex', alignItems: 'flex-start' }}>
  1164. <Typography variant="lionerSize" component="span">
  1165. Remarks:
  1166. </Typography>
  1167. </Grid>
  1168. <Grid item xs={7} sm={7} md={7} lg={7}>
  1169. <TextField
  1170. fullWidth
  1171. {...register("remarks", { value: refClient.remarks })}
  1172. id='remarks'
  1173. required
  1174. disabled={!isEditing}
  1175. inputProps={{ maxLength: 500, style: { fontSize: '1.1rem' } }}
  1176. InputProps={{ style: { minHeight: '42.5px', maxHeight: '50vh' } }}
  1177. multiline
  1178. maxRows={10}
  1179. autoComplete="off"
  1180. />
  1181. </Grid>
  1182. </Grid>
  1183. </Grid>
  1184. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  1185. </Grid>
  1186. <Grid>
  1187. {/* ======================================================================= */}
  1188. {/* --- START: EARNED INCOME 薪酬收入 (Image 1) --- */}
  1189. {/* ======================================================================= */}
  1190. <Grid item xs={12}>
  1191. <Typography variant="h5" sx={{ mt: 3, mb: 1, px: 2, backgroundColor: '#d0d0d0', py: 1, borderRadius: 1 }}>
  1192. EARNED INCOME 薪酬收入
  1193. </Typography>
  1194. <TableContainer component={Paper} elevation={1}>
  1195. <Table size="small" aria-label="earned income table">
  1196. <TableHead sx={{ backgroundColor: '#f0f0f0' }}>
  1197. <TableRow>
  1198. <TableCell sx={{ fontWeight: 'bold', width: '40%' }}></TableCell>
  1199. <TableCell align="center" sx={{ fontWeight: 'bold', width: '30%' }}>Current Year 本年度</TableCell>
  1200. <TableCell align="center" sx={{ fontWeight: 'bold', width: '30%' }}>Last Year 上年度</TableCell>
  1201. </TableRow>
  1202. </TableHead>
  1203. <TableBody>
  1204. {/* Salary */}
  1205. <TableRow>
  1206. <TableCell>Salary 薪酬</TableCell>
  1207. <TableCell align="right">
  1208. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1209. value={formatNumberForDisplay(earnedIncome.salaryCurrent)} onChange={(e) => handleEarnedIncomeChange('salaryCurrent', cleanNumberForState(cleanNumberForState(e.target.value)))}
  1210. />
  1211. </TableCell>
  1212. <TableCell align="right">
  1213. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1214. value={formatNumberForDisplay(earnedIncome.salaryLast)} onChange={(e) => handleEarnedIncomeChange('salaryLast', cleanNumberForState(cleanNumberForState(e.target.value)))}
  1215. />
  1216. </TableCell>
  1217. </TableRow>
  1218. {/* Bonus */}
  1219. <TableRow>
  1220. <TableCell>Bonus 花紅</TableCell>
  1221. <TableCell align="right">
  1222. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1223. value={formatNumberForDisplay(earnedIncome.bonusCurrent)} onChange={(e) => handleEarnedIncomeChange('bonusCurrent', cleanNumberForState(cleanNumberForState(e.target.value)))}
  1224. />
  1225. </TableCell>
  1226. <TableCell align="right">
  1227. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1228. value={formatNumberForDisplay(earnedIncome.bonusLast)} onChange={(e) => handleEarnedIncomeChange('bonusLast', cleanNumberForState(e.target.value))}
  1229. />
  1230. </TableCell>
  1231. </TableRow>
  1232. {/* Other */}
  1233. <TableRow>
  1234. <TableCell>Other 其他</TableCell>
  1235. <TableCell align="right">
  1236. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1237. value={formatNumberForDisplay(earnedIncome.otherEarnedCurrent)} onChange={(e) => handleEarnedIncomeChange('otherEarnedCurrent', cleanNumberForState(e.target.value))}
  1238. />
  1239. </TableCell>
  1240. <TableCell align="right">
  1241. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1242. value={formatNumberForDisplay(earnedIncome.otherEarnedLast)} onChange={(e) => handleEarnedIncomeChange('otherEarnedLast', cleanNumberForState(e.target.value))}
  1243. />
  1244. </TableCell>
  1245. </TableRow>
  1246. {/* Total Earned Income */}
  1247. <TableRow sx={{ '& td': { fontWeight: 'bold', backgroundColor: '#e0e0e0' } }}>
  1248. <TableCell>Total Earned Income 薪酬收入總額</TableCell>
  1249. <TableCell align="right">
  1250. <TextField fullWidth variant="filled" size="small" readOnly
  1251. value={formatNumberForDisplay(totalEarnedCurrent.toFixed(0))}
  1252. />
  1253. </TableCell>
  1254. <TableCell align="right">
  1255. <TextField fullWidth variant="filled" size="small" readOnly
  1256. value={formatNumberForDisplay(totalEarnedLast.toFixed(0))}
  1257. />
  1258. </TableCell>
  1259. </TableRow>
  1260. </TableBody>
  1261. </Table>
  1262. </TableContainer>
  1263. </Grid>
  1264. {/* --- END: EARNED INCOME --- */}
  1265. {/* ======================================================================= */}
  1266. {/* --- START: UNEARNED INCOME 非薪酬收入 (Image 2 - UPDATED) --- */}
  1267. {/* ======================================================================= */}
  1268. <Grid item xs={12}>
  1269. <Typography variant="h5" sx={{ mt: 5, mb: 1, px: 2, backgroundColor: '#d0d0d0', py: 1, borderRadius: 1 }}>
  1270. UNEARNED INCOME 非薪酬收入
  1271. </Typography>
  1272. <TableContainer component={Paper} elevation={1}>
  1273. <Table size="small" aria-label="unearned income table">
  1274. <TableHead sx={{ backgroundColor: '#f0f0f0' }}>
  1275. <TableRow>
  1276. <TableCell sx={{ fontWeight: 'bold', width: '40%' }}></TableCell>
  1277. <TableCell align="center" sx={{ fontWeight: 'bold', width: '30%' }}>Current Year 本年度</TableCell>
  1278. <TableCell align="center" sx={{ fontWeight: 'bold', width: '30%' }}>Last Year 上年度</TableCell>
  1279. </TableRow>
  1280. </TableHead>
  1281. <TableBody>
  1282. {/* Company Interest */}
  1283. <TableRow>
  1284. <TableCell>Company Interest 公司收益</TableCell>
  1285. <TableCell align="right">
  1286. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1287. value={formatNumberForDisplay(unearnedIncome.companyInterestCurrent)} onChange={(e) => handleUnearnedIncomeChange('companyInterestCurrent', cleanNumberForState(e.target.value))}
  1288. />
  1289. </TableCell>
  1290. <TableCell align="right">
  1291. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1292. value={formatNumberForDisplay(unearnedIncome.companyInterestLast)} onChange={(e) => handleUnearnedIncomeChange('companyInterestLast', cleanNumberForState(e.target.value))}
  1293. />
  1294. </TableCell>
  1295. </TableRow>
  1296. {/* Dividends */}
  1297. <TableRow>
  1298. <TableCell>Dividends 股息</TableCell>
  1299. <TableCell align="right">
  1300. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1301. value={formatNumberForDisplay(unearnedIncome.dividendsCurrent)} onChange={(e) => handleUnearnedIncomeChange('dividendsCurrent', cleanNumberForState(e.target.value))}
  1302. />
  1303. </TableCell>
  1304. <TableCell align="right">
  1305. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1306. value={formatNumberForDisplay(unearnedIncome.dividendsLast)} onChange={(e) => handleUnearnedIncomeChange('dividendsLast', cleanNumberForState(e.target.value))}
  1307. />
  1308. </TableCell>
  1309. </TableRow>
  1310. {/* Rentals */}
  1311. <TableRow>
  1312. <TableCell>Rentals 租金</TableCell>
  1313. <TableCell align="right">
  1314. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1315. value={formatNumberForDisplay(unearnedIncome.rentalsCurrent)} onChange={(e) => handleUnearnedIncomeChange('rentalsCurrent', cleanNumberForState(e.target.value))}
  1316. />
  1317. </TableCell>
  1318. <TableCell align="right">
  1319. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1320. value={formatNumberForDisplay(unearnedIncome.rentalsLast)} onChange={(e) => handleUnearnedIncomeChange('rentalsLast', cleanNumberForState(e.target.value))}
  1321. />
  1322. </TableCell>
  1323. </TableRow>
  1324. {/* Investment Income */}
  1325. <TableRow>
  1326. <TableCell>Investment Income 投資收益</TableCell>
  1327. <TableCell align="right">
  1328. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1329. value={formatNumberForDisplay(unearnedIncome.investmentIncomeCurrent)} onChange={(e) => handleUnearnedIncomeChange('investmentIncomeCurrent', cleanNumberForState(e.target.value))}
  1330. />
  1331. </TableCell>
  1332. <TableCell align="right">
  1333. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1334. value={formatNumberForDisplay(unearnedIncome.investmentIncomeLast)} onChange={(e) => handleUnearnedIncomeChange('investmentIncomeLast', cleanNumberForState(e.target.value))}
  1335. />
  1336. </TableCell>
  1337. </TableRow>
  1338. {/* Other Unearned */}
  1339. <TableRow>
  1340. <TableCell>Other 其他</TableCell>
  1341. <TableCell align="right">
  1342. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1343. value={formatNumberForDisplay(unearnedIncome.otherUnearnedCurrent)} onChange={(e) => handleUnearnedIncomeChange('otherUnearnedCurrent', cleanNumberForState(e.target.value))}
  1344. />
  1345. </TableCell>
  1346. <TableCell align="right">
  1347. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1348. value={formatNumberForDisplay(unearnedIncome.otherUnearnedLast)} onChange={(e) => handleUnearnedIncomeChange('otherUnearnedLast', cleanNumberForState(e.target.value))}
  1349. />
  1350. </TableCell>
  1351. </TableRow>
  1352. {/* Total Unearned Income */}
  1353. <TableRow sx={{ '& td': { fontWeight: 'bold', backgroundColor: '#e0e0e0' } }}>
  1354. <TableCell>Total Unearned Income 非薪酬收入總額</TableCell>
  1355. <TableCell align="right">
  1356. <TextField fullWidth variant="filled" size="small" readOnly
  1357. value={formatNumberForDisplay(totalUnearnedCurrent.toFixed(0))}
  1358. />
  1359. </TableCell>
  1360. <TableCell align="right">
  1361. <TextField fullWidth variant="filled" size="small" readOnly
  1362. value={formatNumberForDisplay(totalUnearnedLast.toFixed(0))}
  1363. />
  1364. </TableCell>
  1365. </TableRow>
  1366. {/* Total Income */}
  1367. <TableRow sx={{ '& td': { fontWeight: 'bold', backgroundColor: '#d0d0d0' } }}>
  1368. <TableCell>Total Income 收入總額</TableCell>
  1369. <TableCell align="right">
  1370. <TextField fullWidth variant="filled" size="small" readOnly
  1371. value={formatNumberForDisplay(totalIncomeCurrent.toFixed(0))}
  1372. />
  1373. </TableCell>
  1374. <TableCell align="right">
  1375. <TextField fullWidth variant="filled" size="small" readOnly
  1376. value={formatNumberForDisplay(totalIncomeLast.toFixed(0))}
  1377. />
  1378. </TableCell>
  1379. </TableRow>
  1380. </TableBody>
  1381. </Table>
  1382. </TableContainer>
  1383. </Grid>
  1384. {/* --- END: UNEARNED INCOME --- */}
  1385. {/* ======================================================================= */}
  1386. {/* --- START: EXPENDITURE STATEMENT 開支報表 (Image 3) --- */}
  1387. {/* ======================================================================= */}
  1388. <Grid item xs={12}>
  1389. <Typography variant="h5" sx={{ mt: 5, mb: 1, px: 2, backgroundColor: '#d0d0d0', py: 1, borderRadius: 1 }}>
  1390. Expenditure Statement 開支報表
  1391. </Typography>
  1392. <TableContainer component={Paper} elevation={1}>
  1393. <Table size="small" aria-label="expenditure statement table">
  1394. <TableHead sx={{ backgroundColor: '#f0f0f0' }}>
  1395. <TableRow>
  1396. <TableCell sx={{ fontWeight: 'bold', width: '40%' }}></TableCell>
  1397. <TableCell align="center" sx={{ fontWeight: 'bold', width: '30%' }}>Current Year 本年度</TableCell>
  1398. <TableCell align="center" sx={{ fontWeight: 'bold', width: '30%' }}>Last Year 上年度</TableCell>
  1399. </TableRow>
  1400. </TableHead>
  1401. <TableBody>
  1402. {/* Mortgage */}
  1403. <TableRow>
  1404. <TableCell>Mortgage 按揭</TableCell>
  1405. <TableCell align="right">
  1406. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1407. value={formatNumberForDisplay(expenditure.mortgageCurrent)} onChange={(e) => handleExpenditureChange('mortgageCurrent', cleanNumberForState(e.target.value))}
  1408. />
  1409. </TableCell>
  1410. <TableCell align="right">
  1411. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1412. value={formatNumberForDisplay(expenditure.mortgageLast)} onChange={(e) => handleExpenditureChange('mortgageLast', cleanNumberForState(e.target.value))}
  1413. />
  1414. </TableCell>
  1415. </TableRow>
  1416. {/* Rent */}
  1417. <TableRow>
  1418. <TableCell>Rent 租金</TableCell>
  1419. <TableCell align="right">
  1420. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1421. value={formatNumberForDisplay(expenditure.rentCurrent)} onChange={(e) => handleExpenditureChange('rentCurrent', cleanNumberForState(e.target.value))}
  1422. />
  1423. </TableCell>
  1424. <TableCell align="right">
  1425. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1426. value={formatNumberForDisplay(expenditure.rentLast)} onChange={(e) => handleExpenditureChange('rentLast', cleanNumberForState(e.target.value))}
  1427. />
  1428. </TableCell>
  1429. </TableRow>
  1430. {/* Schooling for Children */}
  1431. <TableRow>
  1432. <TableCell>Schooling for Children 子女教育</TableCell>
  1433. <TableCell align="right">
  1434. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1435. value={formatNumberForDisplay(expenditure.schoolingCurrent)} onChange={(e) => handleExpenditureChange('schoolingCurrent', cleanNumberForState(e.target.value))}
  1436. />
  1437. </TableCell>
  1438. <TableCell align="right">
  1439. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1440. value={formatNumberForDisplay(expenditure.schoolingLast)} onChange={(e) => handleExpenditureChange('schoolingLast', cleanNumberForState(e.target.value))}
  1441. />
  1442. </TableCell>
  1443. </TableRow>
  1444. {/* Memberships */}
  1445. <TableRow>
  1446. <TableCell>Memberships 會籍</TableCell>
  1447. <TableCell align="right">
  1448. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1449. value={formatNumberForDisplay(expenditure.membershipsCurrent)} onChange={(e) => handleExpenditureChange('membershipsCurrent', cleanNumberForState(e.target.value))}
  1450. />
  1451. </TableCell>
  1452. <TableCell align="right">
  1453. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1454. value={formatNumberForDisplay(expenditure.membershipsLast)} onChange={(e) => handleExpenditureChange('membershipsLast', cleanNumberForState(e.target.value))}
  1455. />
  1456. </TableCell>
  1457. </TableRow>
  1458. {/* Other Expenditure */}
  1459. <TableRow>
  1460. <TableCell>Other 其他</TableCell>
  1461. <TableCell align="right">
  1462. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1463. value={formatNumberForDisplay(expenditure.otherExpenditureCurrent)} onChange={(e) => handleExpenditureChange('otherExpenditureCurrent', cleanNumberForState(e.target.value))}
  1464. />
  1465. </TableCell>
  1466. <TableCell align="right">
  1467. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1468. value={formatNumberForDisplay(expenditure.otherExpenditureLast)} onChange={(e) => handleExpenditureChange('otherExpenditureLast', cleanNumberForState(e.target.value))}
  1469. />
  1470. </TableCell>
  1471. </TableRow>
  1472. {/* Interest */}
  1473. <TableRow>
  1474. <TableCell>Interest 利息還款額</TableCell>
  1475. <TableCell align="right">
  1476. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1477. value={formatNumberForDisplay(expenditure.interestCurrent)} onChange={(e) => handleExpenditureChange('interestCurrent', cleanNumberForState(e.target.value))}
  1478. />
  1479. </TableCell>
  1480. <TableCell align="right">
  1481. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1482. value={formatNumberForDisplay(expenditure.interestLast)} onChange={(e) => handleExpenditureChange('interestLast', cleanNumberForState(e.target.value))}
  1483. />
  1484. </TableCell>
  1485. </TableRow>
  1486. {/* Principal */}
  1487. <TableRow>
  1488. <TableCell>Principal 本金還款額</TableCell>
  1489. <TableCell align="right">
  1490. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1491. value={formatNumberForDisplay(expenditure.principalCurrent)} onChange={(e) => handleExpenditureChange('principalCurrent', cleanNumberForState(e.target.value))}
  1492. />
  1493. </TableCell>
  1494. <TableCell align="right">
  1495. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1496. value={formatNumberForDisplay(expenditure.principalLast)} onChange={(e) => handleExpenditureChange('principalLast', cleanNumberForState(e.target.value))}
  1497. />
  1498. </TableCell>
  1499. </TableRow>
  1500. {/* Other */}
  1501. <TableRow>
  1502. <TableCell>Other Loan 其他</TableCell>
  1503. <TableCell align="right">
  1504. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1505. value={formatNumberForDisplay(expenditure.otherPrefFinanceCurrent)} onChange={(e) => handleExpenditureChange('otherPrefFinanceCurrent', cleanNumberForState(e.target.value))}
  1506. />
  1507. </TableCell>
  1508. <TableCell align="right">
  1509. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1510. value={formatNumberForDisplay(expenditure.otherPrefFinanceLast)} onChange={(e) => handleExpenditureChange('otherPrefFinanceLast', cleanNumberForState(e.target.value))}
  1511. />
  1512. </TableCell>
  1513. </TableRow>
  1514. {/* Empty Rows (from your image) - you can remove these if not strictly needed for layout */}
  1515. <TableRow><TableCell></TableCell><TableCell></TableCell><TableCell></TableCell></TableRow>
  1516. <TableRow><TableCell></TableCell><TableCell></TableCell><TableCell></TableCell></TableRow>
  1517. {/* Total Expenditure */}
  1518. <TableRow sx={{ '& td': { fontWeight: 'bold', backgroundColor: '#e0e0e0' } }}>
  1519. <TableCell>Total Expenditure 開支總額</TableCell>
  1520. <TableCell align="right">
  1521. <TextField fullWidth variant="filled" size="small" readOnly
  1522. value={formatNumberForDisplay(totalExpenditureCurrent.toFixed(0))}
  1523. />
  1524. </TableCell>
  1525. <TableCell align="right">
  1526. <TextField fullWidth variant="filled" size="small" readOnly
  1527. value={formatNumberForDisplay(totalExpenditureLast.toFixed(0))}
  1528. />
  1529. </TableCell>
  1530. </TableRow>
  1531. </TableBody>
  1532. </Table>
  1533. </TableContainer>
  1534. </Grid>
  1535. {/* --- END: EXPENDITURE STATEMENT --- */}
  1536. {/* ======================================================================= */}
  1537. {/* --- START: LIQUID & NON-LIQUID ASSET 流動資產 & 非流動資產 (Image 4) --- */}
  1538. {/* ======================================================================= */}
  1539. <Grid item xs={12}>
  1540. <Typography variant="h5" sx={{ mt: 5, mb: 1, px: 2, backgroundColor: '#d0d0d0', py: 1, borderRadius: 1 }}>
  1541. Liquid Asset 流動資產
  1542. </Typography>
  1543. <TableContainer component={Paper} elevation={1}>
  1544. <Table size="small" aria-label="liquid asset table">
  1545. <TableHead sx={{ backgroundColor: '#f0f0f0' }}>
  1546. <TableRow>
  1547. <TableCell sx={{ fontWeight: 'bold', width: '40%' }}></TableCell>
  1548. <TableCell align="center" sx={{ fontWeight: 'bold', width: '30%' }}>Current Year 本年度</TableCell>
  1549. <TableCell align="center" sx={{ fontWeight: 'bold', width: '30%' }}>Last Year 上年度</TableCell>
  1550. </TableRow>
  1551. </TableHead>
  1552. <TableBody>
  1553. {/* Cash and Fixed Deposits */}
  1554. <TableRow>
  1555. <TableCell>Cash and Fixed Deposits 現金與定期存款</TableCell>
  1556. <TableCell align="right">
  1557. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1558. value={formatNumberForDisplay(assets.cashDepositsCurrent)} onChange={(e) => handleAssetsChange('cashDepositsCurrent', cleanNumberForState(e.target.value))}
  1559. />
  1560. </TableCell>
  1561. <TableCell align="right">
  1562. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1563. value={formatNumberForDisplay(assets.cashDepositsLast)} onChange={(e) => handleAssetsChange('cashDepositsLast', cleanNumberForState(e.target.value))}
  1564. />
  1565. </TableCell>
  1566. </TableRow>
  1567. {/* Investments */}
  1568. <TableRow>
  1569. <TableCell>Investments 投資</TableCell>
  1570. <TableCell align="right">
  1571. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1572. value={formatNumberForDisplay(assets.investmentsCurrent)} onChange={(e) => handleAssetsChange('investmentsCurrent', cleanNumberForState(e.target.value))}
  1573. />
  1574. </TableCell>
  1575. <TableCell align="right">
  1576. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1577. value={formatNumberForDisplay(assets.investmentsLast)} onChange={(e) => handleAssetsChange('investmentsLast', cleanNumberForState(e.target.value))}
  1578. />
  1579. </TableCell>
  1580. </TableRow>
  1581. {/* Other Liquid */}
  1582. <TableRow>
  1583. <TableCell>Other 其他</TableCell>
  1584. <TableCell align="right">
  1585. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1586. value={formatNumberForDisplay(assets.otherLiquidCurrent)} onChange={(e) => handleAssetsChange('otherLiquidCurrent', cleanNumberForState(e.target.value))}
  1587. />
  1588. </TableCell>
  1589. <TableCell align="right">
  1590. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1591. value={formatNumberForDisplay(assets.otherLiquidLast)} onChange={(e) => handleAssetsChange('otherLiquidLast', cleanNumberForState(e.target.value))}
  1592. />
  1593. </TableCell>
  1594. </TableRow>
  1595. {/* Total Liquid Asset */}
  1596. <TableRow sx={{ '& td': { fontWeight: 'bold', backgroundColor: '#e0e0e0' } }}>
  1597. <TableCell>Total Liquid Asset 流動資產總額</TableCell>
  1598. <TableCell align="right">
  1599. <TextField fullWidth variant="filled" size="small" readOnly
  1600. value={formatNumberForDisplay(totalLiquidAssetCurrent.toFixed(0))}
  1601. />
  1602. </TableCell>
  1603. <TableCell align="right">
  1604. <TextField fullWidth variant="filled" size="small" readOnly
  1605. value={formatNumberForDisplay(totalLiquidAssetLast.toFixed(0))}
  1606. />
  1607. </TableCell>
  1608. </TableRow>
  1609. </TableBody>
  1610. </Table>
  1611. </TableContainer>
  1612. <Typography variant="h5" sx={{ mt: 3, mb: 1, px: 2, backgroundColor: '#d0d0d0', py: 1, borderRadius: 1 }}>
  1613. Non-Liquid Asset 非流動資產
  1614. </Typography>
  1615. <TableContainer component={Paper} elevation={1}>
  1616. <Table size="small" aria-label="non-liquid asset table">
  1617. <TableHead sx={{ backgroundColor: '#f0f0f0' }}>
  1618. <TableRow>
  1619. <TableCell sx={{ fontWeight: 'bold', width: '40%' }}></TableCell>
  1620. <TableCell align="center" sx={{ fontWeight: 'bold', width: '30%' }}>Current Year 本年度</TableCell>
  1621. <TableCell align="center" sx={{ fontWeight: 'bold', width: '30%' }}>Last Year 上年度</TableCell>
  1622. </TableRow>
  1623. </TableHead>
  1624. <TableBody>
  1625. {/* Net Business Interest */}
  1626. <TableRow>
  1627. <TableCell>Net Business Interest 淨商業利益</TableCell>
  1628. <TableCell align="right">
  1629. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1630. value={formatNumberForDisplay(assets.netBusinessInterestCurrent)} onChange={(e) => handleAssetsChange('netBusinessInterestCurrent', cleanNumberForState(e.target.value))}
  1631. />
  1632. </TableCell>
  1633. <TableCell align="right">
  1634. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1635. value={formatNumberForDisplay(assets.netBusinessInterestLast)} onChange={(e) => handleAssetsChange('netBusinessInterestLast', cleanNumberForState(e.target.value))}
  1636. />
  1637. </TableCell>
  1638. </TableRow>
  1639. {/* Personal Properties */}
  1640. <TableRow>
  1641. <TableCell>Personal Properties 個人財產</TableCell>
  1642. <TableCell align="right">
  1643. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1644. value={formatNumberForDisplay(assets.personalPropertiesCurrent)} onChange={(e) => handleAssetsChange('personalPropertiesCurrent', cleanNumberForState(e.target.value))}
  1645. />
  1646. </TableCell>
  1647. <TableCell align="right">
  1648. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1649. value={formatNumberForDisplay(assets.personalPropertiesLast)} onChange={(e) => handleAssetsChange('personalPropertiesLast', cleanNumberForState(e.target.value))}
  1650. />
  1651. </TableCell>
  1652. </TableRow>
  1653. {/* Real Estate - NEW ROW */}
  1654. <TableRow>
  1655. <TableCell>Real Estate 房地產</TableCell>
  1656. <TableCell align="right">
  1657. <TextField
  1658. onFocus={handleFocus}
  1659. disabled={!isEditing}
  1660. fullWidth
  1661. variant="outlined"
  1662. size="small"
  1663. inputProps={{ min: "0", step: "0.01" }}
  1664. value={formatNumberForDisplay(assets.realEstateCurrent)}
  1665. onChange={(e) => handleAssetsChange('realEstateCurrent', cleanNumberForState(e.target.value))}
  1666. />
  1667. </TableCell>
  1668. <TableCell align="right">
  1669. <TextField
  1670. onFocus={handleFocus}
  1671. disabled={!isEditing}
  1672. fullWidth
  1673. variant="outlined"
  1674. size="small"
  1675. inputProps={{ min: "0", step: "0.01" }}
  1676. value={formatNumberForDisplay(assets.realEstateLast)}
  1677. onChange={(e) => handleAssetsChange('realEstateLast', cleanNumberForState(e.target.value))}
  1678. />
  1679. </TableCell>
  1680. </TableRow>
  1681. {/* Other Non-Liquid */}
  1682. <TableRow>
  1683. <TableCell>Other 其他</TableCell>
  1684. <TableCell align="right">
  1685. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1686. value={formatNumberForDisplay(assets.otherNonLiquidCurrent)} onChange={(e) => handleAssetsChange('otherNonLiquidCurrent', cleanNumberForState(e.target.value))}
  1687. />
  1688. </TableCell>
  1689. <TableCell align="right">
  1690. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1691. value={formatNumberForDisplay(assets.otherNonLiquidLast)} onChange={(e) => handleAssetsChange('otherNonLiquidLast', cleanNumberForState(e.target.value))}
  1692. />
  1693. </TableCell>
  1694. </TableRow>
  1695. {/* Total Non-Liquid Asset */}
  1696. <TableRow sx={{ '& td': { fontWeight: 'bold', backgroundColor: '#e0e0e0' } }}>
  1697. <TableCell>Total Non-Liquid Asset 非流動資產總額</TableCell>
  1698. <TableCell align="right">
  1699. <TextField fullWidth variant="filled" size="small" readOnly
  1700. value={formatNumberForDisplay(totalNonLiquidAssetCurrent.toFixed(0))}
  1701. />
  1702. </TableCell>
  1703. <TableCell align="right">
  1704. <TextField fullWidth variant="filled" size="small" readOnly
  1705. value={formatNumberForDisplay(totalNonLiquidAssetLast.toFixed(0))}
  1706. />
  1707. </TableCell>
  1708. </TableRow>
  1709. {/* Total Assets */}
  1710. <TableRow sx={{ '& td': { fontWeight: 'bold', backgroundColor: '#d0d0d0' } }}>
  1711. <TableCell>Total Assets 資產總額</TableCell>
  1712. <TableCell align="right">
  1713. <TextField fullWidth variant="filled" size="small" readOnly
  1714. value={formatNumberForDisplay(totalAssetsCurrent.toFixed(0))}
  1715. />
  1716. </TableCell>
  1717. <TableCell align="right">
  1718. <TextField fullWidth variant="filled" size="small" readOnly
  1719. value={formatNumberForDisplay(totalAssetsLast.toFixed(0))}
  1720. />
  1721. </TableCell>
  1722. </TableRow>
  1723. </TableBody>
  1724. </Table>
  1725. </TableContainer>
  1726. </Grid>
  1727. {/* --- END: LIQUID & NON-LIQUID ASSET --- */}
  1728. {/* ======================================================================= */}
  1729. {/* --- START: LIABILITIES 負債 (Image 5) --- */}
  1730. {/* ======================================================================= */}
  1731. <Grid item xs={12}>
  1732. <Typography variant="h5" sx={{ mt: 5, mb: 1, px: 2, backgroundColor: '#d0d0d0', py: 1, borderRadius: 1 }}>
  1733. Liabilities 負債
  1734. </Typography>
  1735. <TableContainer component={Paper} elevation={1}>
  1736. <Table size="small" aria-label="liabilities table">
  1737. <TableHead sx={{ backgroundColor: '#f0f0f0' }}>
  1738. <TableRow>
  1739. <TableCell sx={{ fontWeight: 'bold', width: '40%' }}></TableCell>
  1740. <TableCell align="center" sx={{ fontWeight: 'bold', width: '30%' }}>Current Year 本年度</TableCell>
  1741. <TableCell align="center" sx={{ fontWeight: 'bold', width: '30%' }}>Last Year 上年度</TableCell>
  1742. </TableRow>
  1743. </TableHead>
  1744. <TableBody>
  1745. {/* Personal Loans */}
  1746. <TableRow>
  1747. <TableCell>Personal Loans 個人債務</TableCell>
  1748. <TableCell align="right">
  1749. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1750. value={formatNumberForDisplay(liabilities.personalLoansCurrent)} onChange={(e) => handleLiabilitiesChange('personalLoansCurrent', cleanNumberForState(e.target.value))}
  1751. />
  1752. </TableCell>
  1753. <TableCell align="right">
  1754. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1755. value={formatNumberForDisplay(liabilities.personalLoansLast)} onChange={(e) => handleLiabilitiesChange('personalLoansLast', cleanNumberForState(e.target.value))}
  1756. />
  1757. </TableCell>
  1758. </TableRow>
  1759. {/* Mortgages */}
  1760. <TableRow>
  1761. <TableCell>Mortgages 按揭</TableCell>
  1762. <TableCell align="right">
  1763. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1764. value={formatNumberForDisplay(liabilities.mortgagesCurrent)} onChange={(e) => handleLiabilitiesChange('mortgagesCurrent', cleanNumberForState(e.target.value))}
  1765. />
  1766. </TableCell>
  1767. <TableCell align="right">
  1768. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1769. value={formatNumberForDisplay(liabilities.mortgagesLast)} onChange={(e) => handleLiabilitiesChange('mortgagesLast', cleanNumberForState(e.target.value))}
  1770. />
  1771. </TableCell>
  1772. </TableRow>
  1773. {/* Margin Account */}
  1774. <TableRow>
  1775. <TableCell>Margin Account 保證金賬戶</TableCell>
  1776. <TableCell align="right">
  1777. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1778. value={formatNumberForDisplay(liabilities.marginAccountCurrent)} onChange={(e) => handleLiabilitiesChange('marginAccountCurrent', cleanNumberForState(e.target.value))}
  1779. />
  1780. </TableCell>
  1781. <TableCell align="right">
  1782. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1783. value={formatNumberForDisplay(liabilities.marginAccountLast)} onChange={(e) => handleLiabilitiesChange('marginAccountLast', cleanNumberForState(e.target.value))}
  1784. />
  1785. </TableCell>
  1786. </TableRow>
  1787. {/* Loan Guarantees */}
  1788. <TableRow>
  1789. <TableCell>Loan Guarantees 債務擔保</TableCell>
  1790. <TableCell align="right">
  1791. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1792. value={formatNumberForDisplay(liabilities.loanGuaranteesCurrent)} onChange={(e) => handleLiabilitiesChange('loanGuaranteesCurrent', cleanNumberForState(e.target.value))}
  1793. />
  1794. </TableCell>
  1795. <TableCell align="right">
  1796. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1797. value={formatNumberForDisplay(liabilities.loanGuaranteesLast)} onChange={(e) => handleLiabilitiesChange('loanGuaranteesLast', cleanNumberForState(e.target.value))}
  1798. />
  1799. </TableCell>
  1800. </TableRow>
  1801. {/* Banking Facility */}
  1802. <TableRow>
  1803. <TableCell>Banking Facility 銀行貸款</TableCell>
  1804. <TableCell align="right">
  1805. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1806. value={formatNumberForDisplay(liabilities.bankingFacilityCurrent)} onChange={(e) => handleLiabilitiesChange('bankingFacilityCurrent', cleanNumberForState(e.target.value))}
  1807. />
  1808. </TableCell>
  1809. <TableCell align="right">
  1810. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1811. value={formatNumberForDisplay(liabilities.bankingFacilityLast)} onChange={(e) => handleLiabilitiesChange('bankingFacilityLast', cleanNumberForState(e.target.value))}
  1812. />
  1813. </TableCell>
  1814. </TableRow>
  1815. {/* Sub-header for Existing Premium Financing/Policy loan */}
  1816. <TableRow>
  1817. <TableCell colSpan={3} sx={{ fontWeight: 'bold', backgroundColor: '#f0f0f0', textAlign: 'center' }}>
  1818. Existing Premium Financing/ Policy loan 現有保費融資/保單貸款
  1819. </TableCell>
  1820. </TableRow>
  1821. {/* Principal */}
  1822. <TableRow>
  1823. <TableCell>Principal 本金還款額</TableCell>
  1824. <TableCell align="right">
  1825. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1826. value={formatNumberForDisplay(liabilities.prefFinancePrincipalCurrent)} onChange={(e) => handleLiabilitiesChange('prefFinancePrincipalCurrent', cleanNumberForState(e.target.value))}
  1827. />
  1828. </TableCell>
  1829. <TableCell align="right">
  1830. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1831. value={formatNumberForDisplay(liabilities.prefFinancePrincipalLast)} onChange={(e) => handleLiabilitiesChange('prefFinancePrincipalLast', cleanNumberForState(e.target.value))}
  1832. />
  1833. </TableCell>
  1834. </TableRow>
  1835. {/* Other Liabilities */}
  1836. <TableRow>
  1837. <TableCell>Other 其他</TableCell>
  1838. <TableCell align="right">
  1839. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1840. value={formatNumberForDisplay(liabilities.prefFinanceOtherCurrent)} onChange={(e) => handleLiabilitiesChange('prefFinanceOtherCurrent', cleanNumberForState(e.target.value))}
  1841. />
  1842. </TableCell>
  1843. <TableCell align="right">
  1844. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1845. value={formatNumberForDisplay(liabilities.prefFinanceOtherLast)} onChange={(e) => handleLiabilitiesChange('prefFinanceOtherLast', cleanNumberForState(e.target.value))}
  1846. />
  1847. </TableCell>
  1848. </TableRow>
  1849. {/* Total Liabilities */}
  1850. <TableRow sx={{ '& td': { fontWeight: 'bold', backgroundColor: '#d0d0d0' } }}>
  1851. <TableCell>Total Liabilities 負債總額</TableCell>
  1852. <TableCell align="right">
  1853. <TextField fullWidth variant="filled" size="small" readOnly
  1854. value={formatNumberForDisplay(totalLiabilitiesCurrent.toFixed(0))}
  1855. />
  1856. </TableCell>
  1857. <TableCell align="right">
  1858. <TextField fullWidth variant="filled" size="small" readOnly
  1859. value={formatNumberForDisplay(totalLiabilitiesLast.toFixed(0))}
  1860. />
  1861. </TableCell>
  1862. </TableRow>
  1863. </TableBody>
  1864. </Table>
  1865. </TableContainer>
  1866. </Grid>
  1867. {/* --- END: LIABILITIES --- */}
  1868. <Grid item xs={12} sx={{
  1869. minHeight: isEditing ? '100px' : '70px',
  1870. width: '100%'
  1871. }} />
  1872. <Grid></Grid>
  1873. <Grid item xs={12} sx={{
  1874. minHeight: isEditing ? '100px' : '70px',
  1875. width: '100%'
  1876. }} />
  1877. <Grid></Grid>
  1878. {(isEditing) ?
  1879. <Paper
  1880. sx={{
  1881. position: 'fixed',
  1882. bottom: 0,
  1883. left: 0,
  1884. right: 0,
  1885. zIndex: 1300,
  1886. padding: 1.5,
  1887. boxShadow: '0 -4px 12px rgba(0, 0, 0, 0.15)',
  1888. backgroundColor: 'white',
  1889. display: 'flex',
  1890. justifyContent: 'flex-end',
  1891. }}
  1892. >
  1893. <Grid container maxWidth justifyContent="center" alignItems="center" >
  1894. <ThemeProvider theme={LIONER_BUTTON_THEME}>
  1895. <Grid item>
  1896. <Grid container>
  1897. <Grid item sx={{ ml: { xs: 1.5, md: 1.5, lg: 1.5 }, mr: 1.5, mb: 1, mt: 2 }}>
  1898. <Button
  1899. variant="contained"
  1900. color="save"
  1901. onClick={submitData}
  1902. >
  1903. Save
  1904. </Button>
  1905. </Grid>
  1906. <Grid item sx={{ ml: 1.5, mr: 1.5, mb: 1, mt: 2 }}>
  1907. <Button
  1908. variant="contained"
  1909. color="cancel"
  1910. onClick={isNewRecord ? returnSearchPage : updateIsEdit}
  1911. >
  1912. Cancel
  1913. </Button>
  1914. </Grid>
  1915. </Grid>
  1916. </Grid>
  1917. <Grid item>
  1918. <Grid container>
  1919. <ThemeProvider theme={LIONER_LONG_BUTTON_THEME}>
  1920. </ThemeProvider>
  1921. </Grid>
  1922. </Grid>
  1923. </ThemeProvider>
  1924. </Grid>
  1925. </Paper>
  1926. :
  1927. <Paper
  1928. sx={{
  1929. position: 'fixed',
  1930. bottom: 0,
  1931. left: 0,
  1932. right: 0,
  1933. zIndex: 1100, // Ensure it floats above all other content
  1934. padding: 1.5,
  1935. boxShadow: '0 -4px 12px rgba(0, 0, 0, 0.15)', // A shadow to clearly separate the bar
  1936. backgroundColor: 'white', // Set an explicit background color
  1937. display: 'flex',
  1938. justifyContent: 'flex-end', // Push buttons to the right
  1939. }}
  1940. >
  1941. <Grid container justifyContent="flex-end" alignItems="center" sx={{ maxWidth: '1400px', width: '100%', margin: '0 auto', pr: 3, pl: 3 }}>
  1942. <Grid item sx={{ ml: 1, mr: 1 }}>
  1943. {/* The Save button should only show/be enabled when editing */}
  1944. <Button
  1945. type="submit"
  1946. variant="contained"
  1947. color="primary"
  1948. disabled={!isEditing || !ability.can('MAINTAIN', 'CLIENT')} // Disable if not editing
  1949. sx={{ display: isEditing ? 'block' : 'none' }} // Only show when editing
  1950. >
  1951. Save
  1952. </Button>
  1953. </Grid>
  1954. <Grid item sx={{ ml: 1, mr: 1 }}>
  1955. {/* ADDED: onClick={handleEditClick} and conditional display/disabled */}
  1956. <Button
  1957. variant="contained"
  1958. color="info"
  1959. onClick={handleEditClick} // <--- REINSTATED EDIT LOGIC
  1960. disabled={isEditing || !ability.can('MAINTAIN', 'CLIENT')} // Disable if already editing or no permission
  1961. sx={{ display: isEditing ? 'none' : 'block' }} // Only show when not editing
  1962. >
  1963. Edit
  1964. </Button>
  1965. </Grid>
  1966. <Grid item>
  1967. <Button
  1968. variant="contained"
  1969. // ... (rest of Back button styles)
  1970. onClick={returnSearchPage}
  1971. >
  1972. Back
  1973. </Button>
  1974. </Grid>
  1975. </Grid>
  1976. </Paper>
  1977. }
  1978. </Grid>
  1979. </Grid>
  1980. </form>
  1981. </MainCard>
  1982. );
  1983. };
  1984. export default ClientForm;