Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 

2070 строки
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. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  744. <Grid container alignItems={"flex-start"}>
  745. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  746. <Typography variant="lionerSize" component="span">
  747. Case Manager: <Typography sx={{ color: GENERAL_RED_COLOR }} component="span"></Typography>
  748. </Typography>
  749. </Grid>
  750. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  751. <TextField
  752. fullWidth
  753. inputProps={{ maxLength: 50 }}
  754. size="small"
  755. {...register("cm", { value: "N/A" })}
  756. id='cm'
  757. disabled
  758. autoComplete="off"
  759. />
  760. </Grid>
  761. </Grid>
  762. </Grid>
  763. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  764. <Grid container alignItems={"flex-start"}>
  765. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  766. <Typography variant="lionerSize" component="span">
  767. Consultant: <Typography sx={{ color: GENERAL_RED_COLOR }} component="span"></Typography>
  768. </Typography>
  769. </Grid>
  770. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  771. <Autocomplete
  772. disablePortal
  773. id="consultant-combo-box"
  774. options={consultantComboList}
  775. getOptionLabel={(option) => option.name || ""}
  776. isOptionEqualToValue={(option, value) => option.id === value.id}
  777. value={selectedConsultant}
  778. onChange={(e, v) => {
  779. setSelectedConsultant(v);
  780. setValue('consultantId', v); }
  781. }
  782. renderInput={(params) => (
  783. <TextField
  784. {...params}
  785. label="Consultant"
  786. name="consultant"
  787. />
  788. )}
  789. disabled={!isEditing}
  790. />
  791. </Grid>
  792. </Grid>
  793. </Grid>
  794. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  795. <Grid container alignItems={"center"}>
  796. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  797. <Typography variant="lionerSize" component="span">
  798. Rs. Address(Room):
  799. </Typography>
  800. </Grid>
  801. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  802. <TextField
  803. fullWidth
  804. inputProps={{ maxLength: 50 }}
  805. size="small"
  806. {...register("crAddressRoom", { value: refClient.crAddressRoom })}
  807. id='crAddressRoom'
  808. disabled={!isEditing}
  809. autoComplete="off"
  810. />
  811. </Grid>
  812. </Grid>
  813. </Grid>
  814. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  815. <Grid container alignItems={"center"}>
  816. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  817. <Typography variant="lionerSize" component="span">
  818. Rs. Address(Floor):
  819. </Typography>
  820. </Grid>
  821. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  822. <TextField
  823. fullWidth
  824. inputProps={{ maxLength: 50 }}
  825. size="small"
  826. {...register("crAddressFloor", { value: refClient.crAddressFloor })}
  827. id='crAddressFloor'
  828. disabled={!isEditing}
  829. autoComplete="off"
  830. />
  831. </Grid>
  832. </Grid>
  833. </Grid>
  834. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  835. <Grid container alignItems={"center"}>
  836. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  837. <Typography variant="lionerSize" component="span">
  838. Rs. Address(Block):
  839. </Typography>
  840. </Grid>
  841. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  842. <TextField
  843. fullWidth
  844. inputProps={{ maxLength: 50 }}
  845. size="small"
  846. {...register("crAddressBlock", { value: refClient.crAddressBlock })}
  847. id='crAddressBlock'
  848. disabled={!isEditing}
  849. autoComplete="off"
  850. />
  851. </Grid>
  852. </Grid>
  853. </Grid>
  854. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  855. <Grid container alignItems={"center"}>
  856. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  857. <Typography variant="lionerSize" component="span">
  858. Rs. Address(Buliding):
  859. </Typography>
  860. </Grid>
  861. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  862. <TextField
  863. fullWidth
  864. inputProps={{ maxLength: 50 }}
  865. size="small"
  866. {...register("crAddressBuilding", { value: refClient.crAddressBuilding })}
  867. id='crAddressBuilding'
  868. disabled={!isEditing}
  869. autoComplete="off"
  870. />
  871. </Grid>
  872. </Grid>
  873. </Grid>
  874. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  875. <Grid container alignItems={"center"}>
  876. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  877. <Typography variant="lionerSize" component="span">
  878. Rs. Address(Street):
  879. </Typography>
  880. </Grid>
  881. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  882. <TextField
  883. fullWidth
  884. inputProps={{ maxLength: 50 }}
  885. size="small"
  886. {...register("crAddressStreet", { value: refClient.crAddressStreet })}
  887. id='crAddressStreet'
  888. disabled={!isEditing}
  889. autoComplete="off"
  890. />
  891. </Grid>
  892. </Grid>
  893. </Grid>
  894. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  895. <Grid container alignItems={"center"}>
  896. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  897. <Typography variant="lionerSize" component="span">
  898. Rs. Address(Area):
  899. </Typography>
  900. </Grid>
  901. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  902. <TextField
  903. fullWidth
  904. inputProps={{ maxLength: 50 }}
  905. size="small"
  906. {...register("crAddressArea", { value: refClient.crAddressArea })}
  907. id='crAddressArea'
  908. disabled={!isEditing}
  909. autoComplete="off"
  910. />
  911. </Grid>
  912. </Grid>
  913. </Grid>
  914. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  915. <Grid container alignItems={"center"}>
  916. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  917. <Typography variant="lionerSize" component="span">
  918. Rs. Address(City):
  919. </Typography>
  920. </Grid>
  921. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  922. <TextField
  923. fullWidth
  924. inputProps={{ maxLength: 50 }}
  925. size="small"
  926. {...register("crAddressCity", { value: refClient.crAddressCity })}
  927. id='crAddressCity'
  928. disabled={!isEditing}
  929. autoComplete="off"
  930. />
  931. </Grid>
  932. </Grid>
  933. </Grid>
  934. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  935. <Grid container alignItems={"center"}>
  936. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  937. <Typography variant="lionerSize" component="span">
  938. Rs. Address(Country):
  939. </Typography>
  940. </Grid>
  941. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  942. <TextField
  943. fullWidth
  944. inputProps={{ maxLength: 50 }}
  945. size="small"
  946. {...register("crAddressCountry", { value: refClient.crAddressCountry })}
  947. id='crAddressCountry'
  948. disabled={!isEditing}
  949. autoComplete="off"
  950. />
  951. </Grid>
  952. </Grid>
  953. </Grid>
  954. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  955. <Grid container alignItems={"center"}>
  956. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  957. <Typography variant="lionerSize" component="span">
  958. Rs. Address(Postal Code):
  959. </Typography>
  960. </Grid>
  961. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  962. <TextField
  963. fullWidth
  964. inputProps={{ maxLength: 50 }}
  965. size="small"
  966. {...register("crAddressPostalCode", { value: refClient.crAddressPostalCode })}
  967. id='crAddressPostalCode'
  968. disabled={!isEditing}
  969. autoComplete="off"
  970. />
  971. </Grid>
  972. </Grid>
  973. </Grid>
  974. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  975. </Grid>
  976. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  977. <Grid container alignItems={"center"}>
  978. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  979. <Typography variant="lionerSize" component="span">
  980. Corr. Address(Room):
  981. </Typography>
  982. </Grid>
  983. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  984. <TextField
  985. fullWidth
  986. inputProps={{ maxLength: 50 }}
  987. size="small"
  988. {...register("corAddressRoom", { value: refClient.corAddressRoom })}
  989. id='corAddressRoom'
  990. disabled={!isEditing}
  991. autoComplete="off"
  992. />
  993. </Grid>
  994. </Grid>
  995. </Grid>
  996. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  997. <Grid container alignItems={"center"}>
  998. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  999. <Typography variant="lionerSize" component="span">
  1000. Corr. Address(Floor):
  1001. </Typography>
  1002. </Grid>
  1003. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  1004. <TextField
  1005. fullWidth
  1006. inputProps={{ maxLength: 50 }}
  1007. size="small"
  1008. {...register("corAddressFloor", { value: refClient.corAddressFloor })}
  1009. id='corAddressFloor'
  1010. disabled={!isEditing}
  1011. autoComplete="off"
  1012. />
  1013. </Grid>
  1014. </Grid>
  1015. </Grid>
  1016. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  1017. <Grid container alignItems={"center"}>
  1018. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  1019. <Typography variant="lionerSize" component="span">
  1020. Corr. Address(Block):
  1021. </Typography>
  1022. </Grid>
  1023. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  1024. <TextField
  1025. fullWidth
  1026. inputProps={{ maxLength: 50 }}
  1027. size="small"
  1028. {...register("corAddressBlock", { value: refClient.corAddressBlock })}
  1029. id='corAddressBlock'
  1030. disabled={!isEditing}
  1031. autoComplete="off"
  1032. />
  1033. </Grid>
  1034. </Grid>
  1035. </Grid>
  1036. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  1037. <Grid container alignItems={"center"}>
  1038. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  1039. <Typography variant="lionerSize" component="span">
  1040. Corr. Address(Buliding):
  1041. </Typography>
  1042. </Grid>
  1043. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  1044. <TextField
  1045. fullWidth
  1046. inputProps={{ maxLength: 50 }}
  1047. size="small"
  1048. {...register("corAddressBuilding", { value: refClient.corAddressBuilding })}
  1049. id='corAddressBuilding'
  1050. disabled={!isEditing}
  1051. autoComplete="off"
  1052. />
  1053. </Grid>
  1054. </Grid>
  1055. </Grid>
  1056. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  1057. <Grid container alignItems={"center"}>
  1058. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  1059. <Typography variant="lionerSize" component="span">
  1060. Corr. Address(Street):
  1061. </Typography>
  1062. </Grid>
  1063. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  1064. <TextField
  1065. fullWidth
  1066. inputProps={{ maxLength: 50 }}
  1067. size="small"
  1068. {...register("corAddressStreet", { value: refClient.corAddressStreet })}
  1069. id='corAddressStreet'
  1070. disabled={!isEditing}
  1071. autoComplete="off"
  1072. />
  1073. </Grid>
  1074. </Grid>
  1075. </Grid>
  1076. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  1077. <Grid container alignItems={"center"}>
  1078. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  1079. <Typography variant="lionerSize" component="span">
  1080. Corr. Address(Area):
  1081. </Typography>
  1082. </Grid>
  1083. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  1084. <TextField
  1085. fullWidth
  1086. inputProps={{ maxLength: 50 }}
  1087. size="small"
  1088. {...register("corAddressArea", { value: refClient.corAddressArea })}
  1089. id='corAddressArea'
  1090. disabled={!isEditing}
  1091. autoComplete="off"
  1092. />
  1093. </Grid>
  1094. </Grid>
  1095. </Grid>
  1096. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  1097. <Grid container alignItems={"center"}>
  1098. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  1099. <Typography variant="lionerSize" component="span">
  1100. Corr. Address(City):
  1101. </Typography>
  1102. </Grid>
  1103. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  1104. <TextField
  1105. fullWidth
  1106. inputProps={{ maxLength: 50 }}
  1107. size="small"
  1108. {...register("corAddressCity", { value: refClient.corAddressCity })}
  1109. id='corAddressCity'
  1110. disabled={!isEditing}
  1111. autoComplete="off"
  1112. />
  1113. </Grid>
  1114. </Grid>
  1115. </Grid>
  1116. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  1117. <Grid container alignItems={"center"}>
  1118. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  1119. <Typography variant="lionerSize" component="span">
  1120. Corr. Address(Country):
  1121. </Typography>
  1122. </Grid>
  1123. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  1124. <TextField
  1125. fullWidth
  1126. inputProps={{ maxLength: 50 }}
  1127. size="small"
  1128. {...register("corAddressCountry", { value: refClient.corAddressCountry })}
  1129. id='corAddressCountry'
  1130. disabled={!isEditing}
  1131. autoComplete="off"
  1132. />
  1133. </Grid>
  1134. </Grid>
  1135. </Grid>
  1136. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  1137. <Grid container alignItems={"center"}>
  1138. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, display: 'flex', alignItems: 'center' }}>
  1139. <Typography variant="lionerSize" component="span">
  1140. Corr. Address(Postal Code):
  1141. </Typography>
  1142. </Grid>
  1143. <Grid item xs={7} sm={7} md={7} lg={6.5}>
  1144. <TextField
  1145. fullWidth
  1146. inputProps={{ maxLength: 50 }}
  1147. size="small"
  1148. {...register("corAddressPostalCode", { value: refClient.corAddressPostalCode })}
  1149. id='corAddressPostalCode'
  1150. disabled={!isEditing}
  1151. autoComplete="off"
  1152. />
  1153. </Grid>
  1154. </Grid>
  1155. </Grid>
  1156. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  1157. </Grid>
  1158. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3, mt: 1 }}>
  1159. <Grid container alignItems={"flex-start"}>
  1160. <Grid item xs={4} sm={4} md={4} lg={4} sx={{ ml: 3, mr: 3, mt: 1, display: 'flex', alignItems: 'flex-start' }}>
  1161. <Typography variant="lionerSize" component="span">
  1162. Remarks:
  1163. </Typography>
  1164. </Grid>
  1165. <Grid item xs={7} sm={7} md={7} lg={7}>
  1166. <TextField
  1167. fullWidth
  1168. {...register("remarks", { value: refClient.remarks })}
  1169. id='remarks'
  1170. required
  1171. disabled={!isEditing}
  1172. inputProps={{ maxLength: 500, style: { fontSize: '1.1rem' } }}
  1173. InputProps={{ style: { minHeight: '42.5px', maxHeight: '50vh' } }}
  1174. multiline
  1175. maxRows={10}
  1176. autoComplete="off"
  1177. />
  1178. </Grid>
  1179. </Grid>
  1180. </Grid>
  1181. <Grid item xs={12} sm={12} md={12} lg={5.5} sx={{ ml: 3, mr: 3, mb: 3 }}>
  1182. </Grid>
  1183. <Grid>
  1184. {/* ======================================================================= */}
  1185. {/* --- START: EARNED INCOME 薪酬收入 (Image 1) --- */}
  1186. {/* ======================================================================= */}
  1187. <Grid item xs={12}>
  1188. <Typography variant="h5" sx={{ mt: 3, mb: 1, px: 2, backgroundColor: '#d0d0d0', py: 1, borderRadius: 1 }}>
  1189. EARNED INCOME 薪酬收入
  1190. </Typography>
  1191. <TableContainer component={Paper} elevation={1}>
  1192. <Table size="small" aria-label="earned income table">
  1193. <TableHead sx={{ backgroundColor: '#f0f0f0' }}>
  1194. <TableRow>
  1195. <TableCell sx={{ fontWeight: 'bold', width: '40%' }}></TableCell>
  1196. <TableCell align="center" sx={{ fontWeight: 'bold', width: '30%' }}>Current Year 本年度</TableCell>
  1197. <TableCell align="center" sx={{ fontWeight: 'bold', width: '30%' }}>Last Year 上年度</TableCell>
  1198. </TableRow>
  1199. </TableHead>
  1200. <TableBody>
  1201. {/* Salary */}
  1202. <TableRow>
  1203. <TableCell>Salary 薪酬</TableCell>
  1204. <TableCell align="right">
  1205. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1206. value={formatNumberForDisplay(earnedIncome.salaryCurrent)} onChange={(e) => handleEarnedIncomeChange('salaryCurrent', cleanNumberForState(cleanNumberForState(e.target.value)))}
  1207. />
  1208. </TableCell>
  1209. <TableCell align="right">
  1210. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1211. value={formatNumberForDisplay(earnedIncome.salaryLast)} onChange={(e) => handleEarnedIncomeChange('salaryLast', cleanNumberForState(cleanNumberForState(e.target.value)))}
  1212. />
  1213. </TableCell>
  1214. </TableRow>
  1215. {/* Bonus */}
  1216. <TableRow>
  1217. <TableCell>Bonus 花紅</TableCell>
  1218. <TableCell align="right">
  1219. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1220. value={formatNumberForDisplay(earnedIncome.bonusCurrent)} onChange={(e) => handleEarnedIncomeChange('bonusCurrent', cleanNumberForState(cleanNumberForState(e.target.value)))}
  1221. />
  1222. </TableCell>
  1223. <TableCell align="right">
  1224. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1225. value={formatNumberForDisplay(earnedIncome.bonusLast)} onChange={(e) => handleEarnedIncomeChange('bonusLast', cleanNumberForState(e.target.value))}
  1226. />
  1227. </TableCell>
  1228. </TableRow>
  1229. {/* Other */}
  1230. <TableRow>
  1231. <TableCell>Other 其他</TableCell>
  1232. <TableCell align="right">
  1233. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1234. value={formatNumberForDisplay(earnedIncome.otherEarnedCurrent)} onChange={(e) => handleEarnedIncomeChange('otherEarnedCurrent', cleanNumberForState(e.target.value))}
  1235. />
  1236. </TableCell>
  1237. <TableCell align="right">
  1238. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1239. value={formatNumberForDisplay(earnedIncome.otherEarnedLast)} onChange={(e) => handleEarnedIncomeChange('otherEarnedLast', cleanNumberForState(e.target.value))}
  1240. />
  1241. </TableCell>
  1242. </TableRow>
  1243. {/* Total Earned Income */}
  1244. <TableRow sx={{ '& td': { fontWeight: 'bold', backgroundColor: '#e0e0e0' } }}>
  1245. <TableCell>Total Earned Income 薪酬收入總額</TableCell>
  1246. <TableCell align="right">
  1247. <TextField fullWidth variant="filled" size="small" readOnly
  1248. value={formatNumberForDisplay(totalEarnedCurrent.toFixed(0))}
  1249. />
  1250. </TableCell>
  1251. <TableCell align="right">
  1252. <TextField fullWidth variant="filled" size="small" readOnly
  1253. value={formatNumberForDisplay(totalEarnedLast.toFixed(0))}
  1254. />
  1255. </TableCell>
  1256. </TableRow>
  1257. </TableBody>
  1258. </Table>
  1259. </TableContainer>
  1260. </Grid>
  1261. {/* --- END: EARNED INCOME --- */}
  1262. {/* ======================================================================= */}
  1263. {/* --- START: UNEARNED INCOME 非薪酬收入 (Image 2 - UPDATED) --- */}
  1264. {/* ======================================================================= */}
  1265. <Grid item xs={12}>
  1266. <Typography variant="h5" sx={{ mt: 5, mb: 1, px: 2, backgroundColor: '#d0d0d0', py: 1, borderRadius: 1 }}>
  1267. UNEARNED INCOME 非薪酬收入
  1268. </Typography>
  1269. <TableContainer component={Paper} elevation={1}>
  1270. <Table size="small" aria-label="unearned income table">
  1271. <TableHead sx={{ backgroundColor: '#f0f0f0' }}>
  1272. <TableRow>
  1273. <TableCell sx={{ fontWeight: 'bold', width: '40%' }}></TableCell>
  1274. <TableCell align="center" sx={{ fontWeight: 'bold', width: '30%' }}>Current Year 本年度</TableCell>
  1275. <TableCell align="center" sx={{ fontWeight: 'bold', width: '30%' }}>Last Year 上年度</TableCell>
  1276. </TableRow>
  1277. </TableHead>
  1278. <TableBody>
  1279. {/* Company Interest */}
  1280. <TableRow>
  1281. <TableCell>Company Interest 公司收益</TableCell>
  1282. <TableCell align="right">
  1283. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1284. value={formatNumberForDisplay(unearnedIncome.companyInterestCurrent)} onChange={(e) => handleUnearnedIncomeChange('companyInterestCurrent', cleanNumberForState(e.target.value))}
  1285. />
  1286. </TableCell>
  1287. <TableCell align="right">
  1288. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1289. value={formatNumberForDisplay(unearnedIncome.companyInterestLast)} onChange={(e) => handleUnearnedIncomeChange('companyInterestLast', cleanNumberForState(e.target.value))}
  1290. />
  1291. </TableCell>
  1292. </TableRow>
  1293. {/* Dividends */}
  1294. <TableRow>
  1295. <TableCell>Dividends 股息</TableCell>
  1296. <TableCell align="right">
  1297. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1298. value={formatNumberForDisplay(unearnedIncome.dividendsCurrent)} onChange={(e) => handleUnearnedIncomeChange('dividendsCurrent', cleanNumberForState(e.target.value))}
  1299. />
  1300. </TableCell>
  1301. <TableCell align="right">
  1302. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1303. value={formatNumberForDisplay(unearnedIncome.dividendsLast)} onChange={(e) => handleUnearnedIncomeChange('dividendsLast', cleanNumberForState(e.target.value))}
  1304. />
  1305. </TableCell>
  1306. </TableRow>
  1307. {/* Rentals */}
  1308. <TableRow>
  1309. <TableCell>Rentals 租金</TableCell>
  1310. <TableCell align="right">
  1311. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1312. value={formatNumberForDisplay(unearnedIncome.rentalsCurrent)} onChange={(e) => handleUnearnedIncomeChange('rentalsCurrent', cleanNumberForState(e.target.value))}
  1313. />
  1314. </TableCell>
  1315. <TableCell align="right">
  1316. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1317. value={formatNumberForDisplay(unearnedIncome.rentalsLast)} onChange={(e) => handleUnearnedIncomeChange('rentalsLast', cleanNumberForState(e.target.value))}
  1318. />
  1319. </TableCell>
  1320. </TableRow>
  1321. {/* Investment Income */}
  1322. <TableRow>
  1323. <TableCell>Investment Income 投資收益</TableCell>
  1324. <TableCell align="right">
  1325. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1326. value={formatNumberForDisplay(unearnedIncome.investmentIncomeCurrent)} onChange={(e) => handleUnearnedIncomeChange('investmentIncomeCurrent', cleanNumberForState(e.target.value))}
  1327. />
  1328. </TableCell>
  1329. <TableCell align="right">
  1330. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1331. value={formatNumberForDisplay(unearnedIncome.investmentIncomeLast)} onChange={(e) => handleUnearnedIncomeChange('investmentIncomeLast', cleanNumberForState(e.target.value))}
  1332. />
  1333. </TableCell>
  1334. </TableRow>
  1335. {/* Other Unearned */}
  1336. <TableRow>
  1337. <TableCell>Other 其他</TableCell>
  1338. <TableCell align="right">
  1339. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1340. value={formatNumberForDisplay(unearnedIncome.otherUnearnedCurrent)} onChange={(e) => handleUnearnedIncomeChange('otherUnearnedCurrent', cleanNumberForState(e.target.value))}
  1341. />
  1342. </TableCell>
  1343. <TableCell align="right">
  1344. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1345. value={formatNumberForDisplay(unearnedIncome.otherUnearnedLast)} onChange={(e) => handleUnearnedIncomeChange('otherUnearnedLast', cleanNumberForState(e.target.value))}
  1346. />
  1347. </TableCell>
  1348. </TableRow>
  1349. {/* Total Unearned Income */}
  1350. <TableRow sx={{ '& td': { fontWeight: 'bold', backgroundColor: '#e0e0e0' } }}>
  1351. <TableCell>Total Unearned Income 非薪酬收入總額</TableCell>
  1352. <TableCell align="right">
  1353. <TextField fullWidth variant="filled" size="small" readOnly
  1354. value={formatNumberForDisplay(totalUnearnedCurrent.toFixed(0))}
  1355. />
  1356. </TableCell>
  1357. <TableCell align="right">
  1358. <TextField fullWidth variant="filled" size="small" readOnly
  1359. value={formatNumberForDisplay(totalUnearnedLast.toFixed(0))}
  1360. />
  1361. </TableCell>
  1362. </TableRow>
  1363. {/* Total Income */}
  1364. <TableRow sx={{ '& td': { fontWeight: 'bold', backgroundColor: '#d0d0d0' } }}>
  1365. <TableCell>Total Income 收入總額</TableCell>
  1366. <TableCell align="right">
  1367. <TextField fullWidth variant="filled" size="small" readOnly
  1368. value={formatNumberForDisplay(totalIncomeCurrent.toFixed(0))}
  1369. />
  1370. </TableCell>
  1371. <TableCell align="right">
  1372. <TextField fullWidth variant="filled" size="small" readOnly
  1373. value={formatNumberForDisplay(totalIncomeLast.toFixed(0))}
  1374. />
  1375. </TableCell>
  1376. </TableRow>
  1377. </TableBody>
  1378. </Table>
  1379. </TableContainer>
  1380. </Grid>
  1381. {/* --- END: UNEARNED INCOME --- */}
  1382. {/* ======================================================================= */}
  1383. {/* --- START: EXPENDITURE STATEMENT 開支報表 (Image 3) --- */}
  1384. {/* ======================================================================= */}
  1385. <Grid item xs={12}>
  1386. <Typography variant="h5" sx={{ mt: 5, mb: 1, px: 2, backgroundColor: '#d0d0d0', py: 1, borderRadius: 1 }}>
  1387. Expenditure Statement 開支報表
  1388. </Typography>
  1389. <TableContainer component={Paper} elevation={1}>
  1390. <Table size="small" aria-label="expenditure statement table">
  1391. <TableHead sx={{ backgroundColor: '#f0f0f0' }}>
  1392. <TableRow>
  1393. <TableCell sx={{ fontWeight: 'bold', width: '40%' }}></TableCell>
  1394. <TableCell align="center" sx={{ fontWeight: 'bold', width: '30%' }}>Current Year 本年度</TableCell>
  1395. <TableCell align="center" sx={{ fontWeight: 'bold', width: '30%' }}>Last Year 上年度</TableCell>
  1396. </TableRow>
  1397. </TableHead>
  1398. <TableBody>
  1399. {/* Mortgage */}
  1400. <TableRow>
  1401. <TableCell>Mortgage 按揭</TableCell>
  1402. <TableCell align="right">
  1403. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1404. value={formatNumberForDisplay(expenditure.mortgageCurrent)} onChange={(e) => handleExpenditureChange('mortgageCurrent', cleanNumberForState(e.target.value))}
  1405. />
  1406. </TableCell>
  1407. <TableCell align="right">
  1408. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1409. value={formatNumberForDisplay(expenditure.mortgageLast)} onChange={(e) => handleExpenditureChange('mortgageLast', cleanNumberForState(e.target.value))}
  1410. />
  1411. </TableCell>
  1412. </TableRow>
  1413. {/* Rent */}
  1414. <TableRow>
  1415. <TableCell>Rent 租金</TableCell>
  1416. <TableCell align="right">
  1417. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1418. value={formatNumberForDisplay(expenditure.rentCurrent)} onChange={(e) => handleExpenditureChange('rentCurrent', cleanNumberForState(e.target.value))}
  1419. />
  1420. </TableCell>
  1421. <TableCell align="right">
  1422. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1423. value={formatNumberForDisplay(expenditure.rentLast)} onChange={(e) => handleExpenditureChange('rentLast', cleanNumberForState(e.target.value))}
  1424. />
  1425. </TableCell>
  1426. </TableRow>
  1427. {/* Schooling for Children */}
  1428. <TableRow>
  1429. <TableCell>Schooling for Children 子女教育</TableCell>
  1430. <TableCell align="right">
  1431. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1432. value={formatNumberForDisplay(expenditure.schoolingCurrent)} onChange={(e) => handleExpenditureChange('schoolingCurrent', cleanNumberForState(e.target.value))}
  1433. />
  1434. </TableCell>
  1435. <TableCell align="right">
  1436. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1437. value={formatNumberForDisplay(expenditure.schoolingLast)} onChange={(e) => handleExpenditureChange('schoolingLast', cleanNumberForState(e.target.value))}
  1438. />
  1439. </TableCell>
  1440. </TableRow>
  1441. {/* Memberships */}
  1442. <TableRow>
  1443. <TableCell>Memberships 會籍</TableCell>
  1444. <TableCell align="right">
  1445. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1446. value={formatNumberForDisplay(expenditure.membershipsCurrent)} onChange={(e) => handleExpenditureChange('membershipsCurrent', cleanNumberForState(e.target.value))}
  1447. />
  1448. </TableCell>
  1449. <TableCell align="right">
  1450. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1451. value={formatNumberForDisplay(expenditure.membershipsLast)} onChange={(e) => handleExpenditureChange('membershipsLast', cleanNumberForState(e.target.value))}
  1452. />
  1453. </TableCell>
  1454. </TableRow>
  1455. {/* Other Expenditure */}
  1456. <TableRow>
  1457. <TableCell>Other 其他</TableCell>
  1458. <TableCell align="right">
  1459. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1460. value={formatNumberForDisplay(expenditure.otherExpenditureCurrent)} onChange={(e) => handleExpenditureChange('otherExpenditureCurrent', cleanNumberForState(e.target.value))}
  1461. />
  1462. </TableCell>
  1463. <TableCell align="right">
  1464. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1465. value={formatNumberForDisplay(expenditure.otherExpenditureLast)} onChange={(e) => handleExpenditureChange('otherExpenditureLast', cleanNumberForState(e.target.value))}
  1466. />
  1467. </TableCell>
  1468. </TableRow>
  1469. {/* Interest */}
  1470. <TableRow>
  1471. <TableCell>Interest 利息還款額</TableCell>
  1472. <TableCell align="right">
  1473. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1474. value={formatNumberForDisplay(expenditure.interestCurrent)} onChange={(e) => handleExpenditureChange('interestCurrent', cleanNumberForState(e.target.value))}
  1475. />
  1476. </TableCell>
  1477. <TableCell align="right">
  1478. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1479. value={formatNumberForDisplay(expenditure.interestLast)} onChange={(e) => handleExpenditureChange('interestLast', cleanNumberForState(e.target.value))}
  1480. />
  1481. </TableCell>
  1482. </TableRow>
  1483. {/* Principal */}
  1484. <TableRow>
  1485. <TableCell>Principal 本金還款額</TableCell>
  1486. <TableCell align="right">
  1487. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1488. value={formatNumberForDisplay(expenditure.principalCurrent)} onChange={(e) => handleExpenditureChange('principalCurrent', cleanNumberForState(e.target.value))}
  1489. />
  1490. </TableCell>
  1491. <TableCell align="right">
  1492. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1493. value={formatNumberForDisplay(expenditure.principalLast)} onChange={(e) => handleExpenditureChange('principalLast', cleanNumberForState(e.target.value))}
  1494. />
  1495. </TableCell>
  1496. </TableRow>
  1497. {/* Other */}
  1498. <TableRow>
  1499. <TableCell>Other Loan 其他</TableCell>
  1500. <TableCell align="right">
  1501. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1502. value={formatNumberForDisplay(expenditure.otherPrefFinanceCurrent)} onChange={(e) => handleExpenditureChange('otherPrefFinanceCurrent', cleanNumberForState(e.target.value))}
  1503. />
  1504. </TableCell>
  1505. <TableCell align="right">
  1506. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1507. value={formatNumberForDisplay(expenditure.otherPrefFinanceLast)} onChange={(e) => handleExpenditureChange('otherPrefFinanceLast', cleanNumberForState(e.target.value))}
  1508. />
  1509. </TableCell>
  1510. </TableRow>
  1511. {/* Empty Rows (from your image) - you can remove these if not strictly needed for layout */}
  1512. <TableRow><TableCell></TableCell><TableCell></TableCell><TableCell></TableCell></TableRow>
  1513. <TableRow><TableCell></TableCell><TableCell></TableCell><TableCell></TableCell></TableRow>
  1514. {/* Total Expenditure */}
  1515. <TableRow sx={{ '& td': { fontWeight: 'bold', backgroundColor: '#e0e0e0' } }}>
  1516. <TableCell>Total Expenditure 開支總額</TableCell>
  1517. <TableCell align="right">
  1518. <TextField fullWidth variant="filled" size="small" readOnly
  1519. value={formatNumberForDisplay(totalExpenditureCurrent.toFixed(0))}
  1520. />
  1521. </TableCell>
  1522. <TableCell align="right">
  1523. <TextField fullWidth variant="filled" size="small" readOnly
  1524. value={formatNumberForDisplay(totalExpenditureLast.toFixed(0))}
  1525. />
  1526. </TableCell>
  1527. </TableRow>
  1528. </TableBody>
  1529. </Table>
  1530. </TableContainer>
  1531. </Grid>
  1532. {/* --- END: EXPENDITURE STATEMENT --- */}
  1533. {/* ======================================================================= */}
  1534. {/* --- START: LIQUID & NON-LIQUID ASSET 流動資產 & 非流動資產 (Image 4) --- */}
  1535. {/* ======================================================================= */}
  1536. <Grid item xs={12}>
  1537. <Typography variant="h5" sx={{ mt: 5, mb: 1, px: 2, backgroundColor: '#d0d0d0', py: 1, borderRadius: 1 }}>
  1538. Liquid Asset 流動資產
  1539. </Typography>
  1540. <TableContainer component={Paper} elevation={1}>
  1541. <Table size="small" aria-label="liquid asset table">
  1542. <TableHead sx={{ backgroundColor: '#f0f0f0' }}>
  1543. <TableRow>
  1544. <TableCell sx={{ fontWeight: 'bold', width: '40%' }}></TableCell>
  1545. <TableCell align="center" sx={{ fontWeight: 'bold', width: '30%' }}>Current Year 本年度</TableCell>
  1546. <TableCell align="center" sx={{ fontWeight: 'bold', width: '30%' }}>Last Year 上年度</TableCell>
  1547. </TableRow>
  1548. </TableHead>
  1549. <TableBody>
  1550. {/* Cash and Fixed Deposits */}
  1551. <TableRow>
  1552. <TableCell>Cash and Fixed Deposits 現金與定期存款</TableCell>
  1553. <TableCell align="right">
  1554. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1555. value={formatNumberForDisplay(assets.cashDepositsCurrent)} onChange={(e) => handleAssetsChange('cashDepositsCurrent', cleanNumberForState(e.target.value))}
  1556. />
  1557. </TableCell>
  1558. <TableCell align="right">
  1559. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1560. value={formatNumberForDisplay(assets.cashDepositsLast)} onChange={(e) => handleAssetsChange('cashDepositsLast', cleanNumberForState(e.target.value))}
  1561. />
  1562. </TableCell>
  1563. </TableRow>
  1564. {/* Investments */}
  1565. <TableRow>
  1566. <TableCell>Investments 投資</TableCell>
  1567. <TableCell align="right">
  1568. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1569. value={formatNumberForDisplay(assets.investmentsCurrent)} onChange={(e) => handleAssetsChange('investmentsCurrent', cleanNumberForState(e.target.value))}
  1570. />
  1571. </TableCell>
  1572. <TableCell align="right">
  1573. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1574. value={formatNumberForDisplay(assets.investmentsLast)} onChange={(e) => handleAssetsChange('investmentsLast', cleanNumberForState(e.target.value))}
  1575. />
  1576. </TableCell>
  1577. </TableRow>
  1578. {/* Other Liquid */}
  1579. <TableRow>
  1580. <TableCell>Other 其他</TableCell>
  1581. <TableCell align="right">
  1582. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1583. value={formatNumberForDisplay(assets.otherLiquidCurrent)} onChange={(e) => handleAssetsChange('otherLiquidCurrent', cleanNumberForState(e.target.value))}
  1584. />
  1585. </TableCell>
  1586. <TableCell align="right">
  1587. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1588. value={formatNumberForDisplay(assets.otherLiquidLast)} onChange={(e) => handleAssetsChange('otherLiquidLast', cleanNumberForState(e.target.value))}
  1589. />
  1590. </TableCell>
  1591. </TableRow>
  1592. {/* Total Liquid Asset */}
  1593. <TableRow sx={{ '& td': { fontWeight: 'bold', backgroundColor: '#e0e0e0' } }}>
  1594. <TableCell>Total Liquid Asset 流動資產總額</TableCell>
  1595. <TableCell align="right">
  1596. <TextField fullWidth variant="filled" size="small" readOnly
  1597. value={formatNumberForDisplay(totalLiquidAssetCurrent.toFixed(0))}
  1598. />
  1599. </TableCell>
  1600. <TableCell align="right">
  1601. <TextField fullWidth variant="filled" size="small" readOnly
  1602. value={formatNumberForDisplay(totalLiquidAssetLast.toFixed(0))}
  1603. />
  1604. </TableCell>
  1605. </TableRow>
  1606. </TableBody>
  1607. </Table>
  1608. </TableContainer>
  1609. <Typography variant="h5" sx={{ mt: 3, mb: 1, px: 2, backgroundColor: '#d0d0d0', py: 1, borderRadius: 1 }}>
  1610. Non-Liquid Asset 非流動資產
  1611. </Typography>
  1612. <TableContainer component={Paper} elevation={1}>
  1613. <Table size="small" aria-label="non-liquid asset table">
  1614. <TableHead sx={{ backgroundColor: '#f0f0f0' }}>
  1615. <TableRow>
  1616. <TableCell sx={{ fontWeight: 'bold', width: '40%' }}></TableCell>
  1617. <TableCell align="center" sx={{ fontWeight: 'bold', width: '30%' }}>Current Year 本年度</TableCell>
  1618. <TableCell align="center" sx={{ fontWeight: 'bold', width: '30%' }}>Last Year 上年度</TableCell>
  1619. </TableRow>
  1620. </TableHead>
  1621. <TableBody>
  1622. {/* Net Business Interest */}
  1623. <TableRow>
  1624. <TableCell>Net Business Interest 淨商業利益</TableCell>
  1625. <TableCell align="right">
  1626. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1627. value={formatNumberForDisplay(assets.netBusinessInterestCurrent)} onChange={(e) => handleAssetsChange('netBusinessInterestCurrent', cleanNumberForState(e.target.value))}
  1628. />
  1629. </TableCell>
  1630. <TableCell align="right">
  1631. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1632. value={formatNumberForDisplay(assets.netBusinessInterestLast)} onChange={(e) => handleAssetsChange('netBusinessInterestLast', cleanNumberForState(e.target.value))}
  1633. />
  1634. </TableCell>
  1635. </TableRow>
  1636. {/* Personal Properties */}
  1637. <TableRow>
  1638. <TableCell>Personal Properties 個人財產</TableCell>
  1639. <TableCell align="right">
  1640. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1641. value={formatNumberForDisplay(assets.personalPropertiesCurrent)} onChange={(e) => handleAssetsChange('personalPropertiesCurrent', cleanNumberForState(e.target.value))}
  1642. />
  1643. </TableCell>
  1644. <TableCell align="right">
  1645. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1646. value={formatNumberForDisplay(assets.personalPropertiesLast)} onChange={(e) => handleAssetsChange('personalPropertiesLast', cleanNumberForState(e.target.value))}
  1647. />
  1648. </TableCell>
  1649. </TableRow>
  1650. {/* Real Estate - NEW ROW */}
  1651. <TableRow>
  1652. <TableCell>Real Estate 房地產</TableCell>
  1653. <TableCell align="right">
  1654. <TextField
  1655. onFocus={handleFocus}
  1656. disabled={!isEditing}
  1657. fullWidth
  1658. variant="outlined"
  1659. size="small"
  1660. inputProps={{ min: "0", step: "0.01" }}
  1661. value={formatNumberForDisplay(assets.realEstateCurrent)}
  1662. onChange={(e) => handleAssetsChange('realEstateCurrent', cleanNumberForState(e.target.value))}
  1663. />
  1664. </TableCell>
  1665. <TableCell align="right">
  1666. <TextField
  1667. onFocus={handleFocus}
  1668. disabled={!isEditing}
  1669. fullWidth
  1670. variant="outlined"
  1671. size="small"
  1672. inputProps={{ min: "0", step: "0.01" }}
  1673. value={formatNumberForDisplay(assets.realEstateLast)}
  1674. onChange={(e) => handleAssetsChange('realEstateLast', cleanNumberForState(e.target.value))}
  1675. />
  1676. </TableCell>
  1677. </TableRow>
  1678. {/* Other Non-Liquid */}
  1679. <TableRow>
  1680. <TableCell>Other 其他</TableCell>
  1681. <TableCell align="right">
  1682. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1683. value={formatNumberForDisplay(assets.otherNonLiquidCurrent)} onChange={(e) => handleAssetsChange('otherNonLiquidCurrent', cleanNumberForState(e.target.value))}
  1684. />
  1685. </TableCell>
  1686. <TableCell align="right">
  1687. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1688. value={formatNumberForDisplay(assets.otherNonLiquidLast)} onChange={(e) => handleAssetsChange('otherNonLiquidLast', cleanNumberForState(e.target.value))}
  1689. />
  1690. </TableCell>
  1691. </TableRow>
  1692. {/* Total Non-Liquid Asset */}
  1693. <TableRow sx={{ '& td': { fontWeight: 'bold', backgroundColor: '#e0e0e0' } }}>
  1694. <TableCell>Total Non-Liquid Asset 非流動資產總額</TableCell>
  1695. <TableCell align="right">
  1696. <TextField fullWidth variant="filled" size="small" readOnly
  1697. value={formatNumberForDisplay(totalNonLiquidAssetCurrent.toFixed(0))}
  1698. />
  1699. </TableCell>
  1700. <TableCell align="right">
  1701. <TextField fullWidth variant="filled" size="small" readOnly
  1702. value={formatNumberForDisplay(totalNonLiquidAssetLast.toFixed(0))}
  1703. />
  1704. </TableCell>
  1705. </TableRow>
  1706. {/* Total Assets */}
  1707. <TableRow sx={{ '& td': { fontWeight: 'bold', backgroundColor: '#d0d0d0' } }}>
  1708. <TableCell>Total Assets 資產總額</TableCell>
  1709. <TableCell align="right">
  1710. <TextField fullWidth variant="filled" size="small" readOnly
  1711. value={formatNumberForDisplay(totalAssetsCurrent.toFixed(0))}
  1712. />
  1713. </TableCell>
  1714. <TableCell align="right">
  1715. <TextField fullWidth variant="filled" size="small" readOnly
  1716. value={formatNumberForDisplay(totalAssetsLast.toFixed(0))}
  1717. />
  1718. </TableCell>
  1719. </TableRow>
  1720. </TableBody>
  1721. </Table>
  1722. </TableContainer>
  1723. </Grid>
  1724. {/* --- END: LIQUID & NON-LIQUID ASSET --- */}
  1725. {/* ======================================================================= */}
  1726. {/* --- START: LIABILITIES 負債 (Image 5) --- */}
  1727. {/* ======================================================================= */}
  1728. <Grid item xs={12}>
  1729. <Typography variant="h5" sx={{ mt: 5, mb: 1, px: 2, backgroundColor: '#d0d0d0', py: 1, borderRadius: 1 }}>
  1730. Liabilities 負債
  1731. </Typography>
  1732. <TableContainer component={Paper} elevation={1}>
  1733. <Table size="small" aria-label="liabilities table">
  1734. <TableHead sx={{ backgroundColor: '#f0f0f0' }}>
  1735. <TableRow>
  1736. <TableCell sx={{ fontWeight: 'bold', width: '40%' }}></TableCell>
  1737. <TableCell align="center" sx={{ fontWeight: 'bold', width: '30%' }}>Current Year 本年度</TableCell>
  1738. <TableCell align="center" sx={{ fontWeight: 'bold', width: '30%' }}>Last Year 上年度</TableCell>
  1739. </TableRow>
  1740. </TableHead>
  1741. <TableBody>
  1742. {/* Personal Loans */}
  1743. <TableRow>
  1744. <TableCell>Personal Loans 個人債務</TableCell>
  1745. <TableCell align="right">
  1746. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1747. value={formatNumberForDisplay(liabilities.personalLoansCurrent)} onChange={(e) => handleLiabilitiesChange('personalLoansCurrent', cleanNumberForState(e.target.value))}
  1748. />
  1749. </TableCell>
  1750. <TableCell align="right">
  1751. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1752. value={formatNumberForDisplay(liabilities.personalLoansLast)} onChange={(e) => handleLiabilitiesChange('personalLoansLast', cleanNumberForState(e.target.value))}
  1753. />
  1754. </TableCell>
  1755. </TableRow>
  1756. {/* Mortgages */}
  1757. <TableRow>
  1758. <TableCell>Mortgages 按揭</TableCell>
  1759. <TableCell align="right">
  1760. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1761. value={formatNumberForDisplay(liabilities.mortgagesCurrent)} onChange={(e) => handleLiabilitiesChange('mortgagesCurrent', cleanNumberForState(e.target.value))}
  1762. />
  1763. </TableCell>
  1764. <TableCell align="right">
  1765. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1766. value={formatNumberForDisplay(liabilities.mortgagesLast)} onChange={(e) => handleLiabilitiesChange('mortgagesLast', cleanNumberForState(e.target.value))}
  1767. />
  1768. </TableCell>
  1769. </TableRow>
  1770. {/* Margin Account */}
  1771. <TableRow>
  1772. <TableCell>Margin Account 保證金賬戶</TableCell>
  1773. <TableCell align="right">
  1774. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1775. value={formatNumberForDisplay(liabilities.marginAccountCurrent)} onChange={(e) => handleLiabilitiesChange('marginAccountCurrent', cleanNumberForState(e.target.value))}
  1776. />
  1777. </TableCell>
  1778. <TableCell align="right">
  1779. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1780. value={formatNumberForDisplay(liabilities.marginAccountLast)} onChange={(e) => handleLiabilitiesChange('marginAccountLast', cleanNumberForState(e.target.value))}
  1781. />
  1782. </TableCell>
  1783. </TableRow>
  1784. {/* Loan Guarantees */}
  1785. <TableRow>
  1786. <TableCell>Loan Guarantees 債務擔保</TableCell>
  1787. <TableCell align="right">
  1788. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1789. value={formatNumberForDisplay(liabilities.loanGuaranteesCurrent)} onChange={(e) => handleLiabilitiesChange('loanGuaranteesCurrent', cleanNumberForState(e.target.value))}
  1790. />
  1791. </TableCell>
  1792. <TableCell align="right">
  1793. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1794. value={formatNumberForDisplay(liabilities.loanGuaranteesLast)} onChange={(e) => handleLiabilitiesChange('loanGuaranteesLast', cleanNumberForState(e.target.value))}
  1795. />
  1796. </TableCell>
  1797. </TableRow>
  1798. {/* Banking Facility */}
  1799. <TableRow>
  1800. <TableCell>Banking Facility 銀行貸款</TableCell>
  1801. <TableCell align="right">
  1802. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1803. value={formatNumberForDisplay(liabilities.bankingFacilityCurrent)} onChange={(e) => handleLiabilitiesChange('bankingFacilityCurrent', cleanNumberForState(e.target.value))}
  1804. />
  1805. </TableCell>
  1806. <TableCell align="right">
  1807. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1808. value={formatNumberForDisplay(liabilities.bankingFacilityLast)} onChange={(e) => handleLiabilitiesChange('bankingFacilityLast', cleanNumberForState(e.target.value))}
  1809. />
  1810. </TableCell>
  1811. </TableRow>
  1812. {/* Sub-header for Existing Premium Financing/Policy loan */}
  1813. <TableRow>
  1814. <TableCell colSpan={3} sx={{ fontWeight: 'bold', backgroundColor: '#f0f0f0', textAlign: 'center' }}>
  1815. Existing Premium Financing/ Policy loan 現有保費融資/保單貸款
  1816. </TableCell>
  1817. </TableRow>
  1818. {/* Principal */}
  1819. <TableRow>
  1820. <TableCell>Principal 本金還款額</TableCell>
  1821. <TableCell align="right">
  1822. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1823. value={formatNumberForDisplay(liabilities.prefFinancePrincipalCurrent)} onChange={(e) => handleLiabilitiesChange('prefFinancePrincipalCurrent', cleanNumberForState(e.target.value))}
  1824. />
  1825. </TableCell>
  1826. <TableCell align="right">
  1827. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1828. value={formatNumberForDisplay(liabilities.prefFinancePrincipalLast)} onChange={(e) => handleLiabilitiesChange('prefFinancePrincipalLast', cleanNumberForState(e.target.value))}
  1829. />
  1830. </TableCell>
  1831. </TableRow>
  1832. {/* Other Liabilities */}
  1833. <TableRow>
  1834. <TableCell>Other 其他</TableCell>
  1835. <TableCell align="right">
  1836. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1837. value={formatNumberForDisplay(liabilities.prefFinanceOtherCurrent)} onChange={(e) => handleLiabilitiesChange('prefFinanceOtherCurrent', cleanNumberForState(e.target.value))}
  1838. />
  1839. </TableCell>
  1840. <TableCell align="right">
  1841. <TextField onFocus={handleFocus} disabled={!isEditing} fullWidth variant="outlined" size="small" inputProps={{ min: "0", step: "0.01" }}
  1842. value={formatNumberForDisplay(liabilities.prefFinanceOtherLast)} onChange={(e) => handleLiabilitiesChange('prefFinanceOtherLast', cleanNumberForState(e.target.value))}
  1843. />
  1844. </TableCell>
  1845. </TableRow>
  1846. {/* Total Liabilities */}
  1847. <TableRow sx={{ '& td': { fontWeight: 'bold', backgroundColor: '#d0d0d0' } }}>
  1848. <TableCell>Total Liabilities 負債總額</TableCell>
  1849. <TableCell align="right">
  1850. <TextField fullWidth variant="filled" size="small" readOnly
  1851. value={formatNumberForDisplay(totalLiabilitiesCurrent.toFixed(0))}
  1852. />
  1853. </TableCell>
  1854. <TableCell align="right">
  1855. <TextField fullWidth variant="filled" size="small" readOnly
  1856. value={formatNumberForDisplay(totalLiabilitiesLast.toFixed(0))}
  1857. />
  1858. </TableCell>
  1859. </TableRow>
  1860. </TableBody>
  1861. </Table>
  1862. </TableContainer>
  1863. </Grid>
  1864. {/* --- END: LIABILITIES --- */}
  1865. <Grid item xs={12} sx={{
  1866. minHeight: isEditing ? '100px' : '70px',
  1867. width: '100%'
  1868. }} />
  1869. <Grid></Grid>
  1870. <Grid item xs={12} sx={{
  1871. minHeight: isEditing ? '100px' : '70px',
  1872. width: '100%'
  1873. }} />
  1874. <Grid></Grid>
  1875. {(isEditing) ?
  1876. <Paper
  1877. sx={{
  1878. position: 'fixed',
  1879. bottom: 0,
  1880. left: 0,
  1881. right: 0,
  1882. zIndex: 1300,
  1883. padding: 1.5,
  1884. boxShadow: '0 -4px 12px rgba(0, 0, 0, 0.15)',
  1885. backgroundColor: 'white',
  1886. display: 'flex',
  1887. justifyContent: 'flex-end',
  1888. }}
  1889. >
  1890. <Grid container maxWidth justifyContent="center" alignItems="center" >
  1891. <ThemeProvider theme={LIONER_BUTTON_THEME}>
  1892. <Grid item>
  1893. <Grid container>
  1894. <Grid item sx={{ ml: { xs: 1.5, md: 1.5, lg: 1.5 }, mr: 1.5, mb: 1, mt: 2 }}>
  1895. <Button
  1896. variant="contained"
  1897. color="save"
  1898. onClick={submitData}
  1899. >
  1900. Save
  1901. </Button>
  1902. </Grid>
  1903. <Grid item sx={{ ml: 1.5, mr: 1.5, mb: 1, mt: 2 }}>
  1904. <Button
  1905. variant="contained"
  1906. color="cancel"
  1907. onClick={isNewRecord ? returnSearchPage : updateIsEdit}
  1908. >
  1909. Cancel
  1910. </Button>
  1911. </Grid>
  1912. </Grid>
  1913. </Grid>
  1914. <Grid item>
  1915. <Grid container>
  1916. <ThemeProvider theme={LIONER_LONG_BUTTON_THEME}>
  1917. </ThemeProvider>
  1918. </Grid>
  1919. </Grid>
  1920. </ThemeProvider>
  1921. </Grid>
  1922. </Paper>
  1923. :
  1924. <Paper
  1925. sx={{
  1926. position: 'fixed',
  1927. bottom: 0,
  1928. left: 0,
  1929. right: 0,
  1930. zIndex: 1100, // Ensure it floats above all other content
  1931. padding: 1.5,
  1932. boxShadow: '0 -4px 12px rgba(0, 0, 0, 0.15)', // A shadow to clearly separate the bar
  1933. backgroundColor: 'white', // Set an explicit background color
  1934. display: 'flex',
  1935. justifyContent: 'flex-end', // Push buttons to the right
  1936. }}
  1937. >
  1938. <Grid container justifyContent="flex-end" alignItems="center" sx={{ maxWidth: '1400px', width: '100%', margin: '0 auto', pr: 3, pl: 3 }}>
  1939. <Grid item sx={{ ml: 1, mr: 1 }}>
  1940. {/* The Save button should only show/be enabled when editing */}
  1941. <Button
  1942. type="submit"
  1943. variant="contained"
  1944. color="primary"
  1945. disabled={!isEditing || !ability.can('MAINTAIN', 'CLIENT')} // Disable if not editing
  1946. sx={{ display: isEditing ? 'block' : 'none' }} // Only show when editing
  1947. >
  1948. Save
  1949. </Button>
  1950. </Grid>
  1951. <Grid item sx={{ ml: 1, mr: 1 }}>
  1952. {/* ADDED: onClick={handleEditClick} and conditional display/disabled */}
  1953. <Button
  1954. variant="contained"
  1955. color="info"
  1956. onClick={handleEditClick} // <--- REINSTATED EDIT LOGIC
  1957. disabled={isEditing || !ability.can('MAINTAIN', 'CLIENT')} // Disable if already editing or no permission
  1958. sx={{ display: isEditing ? 'none' : 'block' }} // Only show when not editing
  1959. >
  1960. Edit
  1961. </Button>
  1962. </Grid>
  1963. <Grid item>
  1964. <Button
  1965. variant="contained"
  1966. // ... (rest of Back button styles)
  1967. onClick={returnSearchPage}
  1968. >
  1969. Back
  1970. </Button>
  1971. </Grid>
  1972. </Grid>
  1973. </Paper>
  1974. }
  1975. </Grid>
  1976. </Grid>
  1977. </form>
  1978. </MainCard>
  1979. );
  1980. };
  1981. export default ClientForm;