refactoring components to match the optimized projections
This commit is contained in:
@@ -16,7 +16,15 @@ export interface LocationCardProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const LocationCard: FC<LocationCardProps> = ({ location, currency }) => {
|
export const LocationCard: FC<LocationCardProps> = ({ location, currency }) => {
|
||||||
const { _id, name, yearMonth, bills, seenByTenant, utilBillsProofOfPaymentAttachment } = location;
|
const {
|
||||||
|
_id,
|
||||||
|
name,
|
||||||
|
yearMonth,
|
||||||
|
bills,
|
||||||
|
seenByTenant,
|
||||||
|
// NOTE: only the fileName is projected from the DB to reduce data transfer
|
||||||
|
utilBillsProofOfPaymentAttachment
|
||||||
|
} = location;
|
||||||
|
|
||||||
const t = useTranslations("home-page.location-card");
|
const t = useTranslations("home-page.location-card");
|
||||||
const currentLocale = useLocale();
|
const currentLocale = useLocale();
|
||||||
|
|||||||
@@ -124,17 +124,17 @@ export const MonthLocationList:React.FC<MonthLocationListProps > = ({
|
|||||||
<AddMonthButton yearMonth={getNextYearMonth(monthsArray[0][1].locations[0].yearMonth)} />
|
<AddMonthButton yearMonth={getNextYearMonth(monthsArray[0][1].locations[0].yearMonth)} />
|
||||||
{
|
{
|
||||||
monthsArray.map(([monthKey, { yearMonth, locations, monthlyExpense }], monthIx) =>
|
monthsArray.map(([monthKey, { yearMonth, locations, monthlyExpense }], monthIx) =>
|
||||||
<MonthCard yearMonth={yearMonth} key={`month-${monthKey}`} monthlyExpense={monthlyExpense} currency={userSettings?.currency} expanded={ yearMonth.month === expandedMonth } onToggle={handleMonthToggle} >
|
<MonthCard yearMonth={yearMonth} key={`month-${monthKey}`} monthlyExpense={monthlyExpense} currency={userSettings?.currency} expanded={ yearMonth.month === expandedMonth } onToggle={handleMonthToggle} >
|
||||||
{
|
{
|
||||||
yearMonth.month === expandedMonth ?
|
yearMonth.month === expandedMonth ?
|
||||||
locations.map((location, ix) => <LocationCard key={`location-${location._id}`} location={location} currency={userSettings?.currency} />)
|
locations.map((location, ix) => <LocationCard key={`location-${location._id}`} location={location} currency={userSettings?.currency} />)
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
<div className="flex gap-2 justify-center">
|
<div className="flex gap-2 justify-center">
|
||||||
<AddLocationButton yearMonth={yearMonth} />
|
<AddLocationButton yearMonth={yearMonth} />
|
||||||
<PrintButton yearMonth={yearMonth} />
|
<PrintButton yearMonth={yearMonth} />
|
||||||
</div>
|
</div>
|
||||||
</MonthCard>
|
</MonthCard>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
<div className="mt-5 flex w-full justify-center">
|
<div className="mt-5 flex w-full justify-center">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { FC, useState } from "react";
|
import { FC, useState } from "react";
|
||||||
import { BilledTo, BillingLocation, UserSettings } from "../lib/db-types";
|
import { BillAttachment, BilledTo, BillingLocation, UserSettings } from "../lib/db-types";
|
||||||
import { formatYearMonth } from "../lib/format";
|
import { formatYearMonth } from "../lib/format";
|
||||||
import { formatCurrency } from "../lib/formatStrings";
|
import { formatCurrency } from "../lib/formatStrings";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
@@ -19,13 +19,24 @@ export interface ViewLocationCardProps {
|
|||||||
|
|
||||||
export const ViewLocationCard:FC<ViewLocationCardProps> = ({location, userSettings}) => {
|
export const ViewLocationCard:FC<ViewLocationCardProps> = ({location, userSettings}) => {
|
||||||
|
|
||||||
const { _id, name: locationName, yearMonth, bills, tenantName, tenantStreet, tenantTown, generateTenantCode, utilBillsProofOfPaymentAttachment } = location;
|
const {
|
||||||
|
_id,
|
||||||
|
name: locationName,
|
||||||
|
yearMonth,
|
||||||
|
bills,
|
||||||
|
tenantName,
|
||||||
|
tenantStreet,
|
||||||
|
tenantTown,
|
||||||
|
generateTenantCode,
|
||||||
|
// NOTE: only the fileName is projected from the DB to reduce data transfer
|
||||||
|
utilBillsProofOfPaymentAttachment
|
||||||
|
} = location;
|
||||||
|
|
||||||
const t = useTranslations("home-page.location-card");
|
const t = useTranslations("home-page.location-card");
|
||||||
|
|
||||||
const [isUploading, setIsUploading] = useState(false);
|
const [isUploading, setIsUploading] = useState(false);
|
||||||
const [uploadError, setUploadError] = useState<string | null>(null);
|
const [uploadError, setUploadError] = useState<string | null>(null);
|
||||||
const [attachment, setAttachment] = useState(utilBillsProofOfPaymentAttachment);
|
const [attachmentFilename, setAttachmentFilename] = useState(utilBillsProofOfPaymentAttachment?.fileName);
|
||||||
|
|
||||||
const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const file = e.target.files?.[0];
|
const file = e.target.files?.[0];
|
||||||
@@ -48,14 +59,7 @@ export const ViewLocationCard:FC<ViewLocationCardProps> = ({location, userSettin
|
|||||||
const result = await uploadUtilBillsProofOfPayment(_id, formData);
|
const result = await uploadUtilBillsProofOfPayment(_id, formData);
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
// Update local state with the uploaded attachment
|
setAttachmentFilename(file.name);
|
||||||
setAttachment({
|
|
||||||
fileName: file.name,
|
|
||||||
fileSize: file.size,
|
|
||||||
fileType: file.type,
|
|
||||||
fileLastModified: file.lastModified,
|
|
||||||
fileContentsBase64: '', // We don't need the contents in the UI
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
setUploadError(result.error || 'Upload failed');
|
setUploadError(result.error || 'Upload failed');
|
||||||
}
|
}
|
||||||
@@ -127,7 +131,7 @@ export const ViewLocationCard:FC<ViewLocationCardProps> = ({location, userSettin
|
|||||||
<fieldset className="fieldset bg-base-200 border-base-300 rounded-box w-xs border p-4 pb-2 pt-0 mt-2">
|
<fieldset className="fieldset bg-base-200 border-base-300 rounded-box w-xs border p-4 pb-2 pt-0 mt-2">
|
||||||
<legend className="fieldset-legend font-semibold uppercase">{t("upload-proof-of-payment-legend")}</legend>
|
<legend className="fieldset-legend font-semibold uppercase">{t("upload-proof-of-payment-legend")}</legend>
|
||||||
|
|
||||||
{attachment ? (
|
{attachmentFilename ? (
|
||||||
<div className="mt-3 ml-[-.5rem]">
|
<div className="mt-3 ml-[-.5rem]">
|
||||||
<Link
|
<Link
|
||||||
href={`/share/proof-of-payment/${_id}/`}
|
href={`/share/proof-of-payment/${_id}/`}
|
||||||
@@ -135,7 +139,7 @@ export const ViewLocationCard:FC<ViewLocationCardProps> = ({location, userSettin
|
|||||||
className='text-center w-full max-w-[20rem] text-nowrap truncate inline-block'
|
className='text-center w-full max-w-[20rem] text-nowrap truncate inline-block'
|
||||||
>
|
>
|
||||||
<DocumentIcon className="h-[1em] w-[1em] text-2xl inline-block mr-1" />
|
<DocumentIcon className="h-[1em] w-[1em] text-2xl inline-block mr-1" />
|
||||||
{decodeURIComponent(attachment.fileName)}
|
{decodeURIComponent(attachmentFilename)}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
Reference in New Issue
Block a user