Skip to content

Commit 9cea2da

Browse files
committed
quality: refactor index.tsx for better maintenability
1 parent 467041d commit 9cea2da

File tree

3 files changed

+322
-191
lines changed

3 files changed

+322
-191
lines changed

client/src/components/icons.tsx

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -313,26 +313,14 @@ export const EditIcon = React.memo(({
313313
stroke={color}
314314
strokeLinecap="round"
315315
strokeLinejoin="round"
316-
strokeWidth="2"
316+
strokeWidth="1.5"
317317
viewBox="0 0 24 24"
318318
width={size || width}
319319
xmlns="http://www.w3.org/2000/svg"
320320
{...props}
321321
>
322-
<g>
323-
<g>
324-
<path d="M389.844,182.85c-6.743,0-12.21,5.467-12.21,12.21v222.968c0,23.562-19.174,42.735-42.736,42.735H67.157
325-
c-23.562,0-42.736-19.174-42.736-42.735V150.285c0-23.562,19.174-42.735,42.736-42.735h267.741c6.743,0,12.21-5.467,12.21-12.21
326-
s-5.467-12.21-12.21-12.21H67.157C30.126,83.13,0,113.255,0,150.285v267.743c0,37.029,30.126,67.155,67.157,67.155h267.741
327-
c37.03,0,67.156-30.126,67.156-67.155V195.061C402.054,188.318,396.587,182.85,389.844,182.85z"/>
328-
<path d="M483.876,20.791c-14.72-14.72-38.669-14.714-53.377,0L221.352,229.944c-0.28,0.28-3.434,3.559-4.251,5.396l-28.963,65.069
329-
c-2.057,4.619-1.056,10.027,2.521,13.6c2.337,2.336,5.461,3.576,8.639,3.576c1.675,0,3.362-0.346,4.96-1.057l65.07-28.963
330-
c1.83-0.815,5.114-3.97,5.396-4.25L483.876,74.169c7.131-7.131,11.06-16.61,11.06-26.692
331-
C494.936,37.396,491.007,27.915,483.876,20.791z M466.61,56.897L257.457,266.05c-0.035,0.036-0.055,0.078-0.089,0.107
332-
l-33.989,15.131L238.51,247.3c0.03-0.036,0.071-0.055,0.107-0.09L447.765,38.058c5.038-5.039,13.819-5.033,18.846,0.005
333-
c2.518,2.51,3.905,5.855,3.905,9.414C470.516,51.036,469.127,54.38,466.61,56.897z"/>
334-
</g>
335-
</g>
322+
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" />
323+
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" />
336324
</svg>
337325
);
338326
}

client/src/pages/index.tsx

Lines changed: 16 additions & 176 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import { usePurchaseAmounts } from "./page-components/usePurchaseAmounts";
4949
import { ActionCell } from "./page-components/ActionCell";
5050
import { StatusCell } from "./page-components/StatusCell";
5151
import { PurchaseIdCell } from "./page-components/PurchaseIdCell";
52+
import { usePurchaseTableColumns } from "./page-components/purchaseTableColumns";
5253

5354
/**
5455
* Main page of the application displaying purchase data in a tabular format
@@ -149,34 +150,6 @@ export default function IndexPage() {
149150
setRefreshTrigger((prev) => prev + 1);
150151
};
151152

152-
/**
153-
* Renders the action column for a purchase row based on its status
154-
*
155-
* The available actions depend on the purchase status:
156-
* - If refunded, displays a "Refunded" label
157-
* - If no feedback, shows "Create Feedback" button
158-
* - If has feedback but no publication, shows "Publish Feedback" button
159-
* - If has feedback and publication, shows "Refund" button
160-
*
161-
* @param {Object} item - The purchase item data
162-
* @param {string} item.purchase - Purchase ID
163-
* @param {boolean} item.refunded - Whether the purchase has been refunded
164-
* @param {boolean} item.hasFeedback - Whether the purchase has feedback
165-
* @param {boolean} item.hasPublication - Whether the feedback has been published
166-
* @param {number} item.amount - The purchase amount
167-
* @returns {JSX.Element} The rendered action column content
168-
*/
169-
const renderActionColumn = (item: PurchaseStatus) => (
170-
<ActionCell
171-
item={item}
172-
hasWritePermission={hasWritePermission}
173-
onCreateFeedback={handleCreateFeedback}
174-
onReturnItem={handleReturnItem}
175-
onPublishFeedback={handlePublishFeedback}
176-
onRefundPurchase={handleRefundPurchases}
177-
/>
178-
);
179-
180153
/**
181154
* Handles opening the return modal for a specific purchase
182155
* Show a confirmation Modal to confirm the return
@@ -240,6 +213,19 @@ export default function IndexPage() {
240213
setGeneratePublicLink(true);
241214
};
242215

216+
// Use custom hook for table columns configuration
217+
const { columns, emptyContent } = usePurchaseTableColumns({
218+
hasWritePermission,
219+
onCreateFeedback: handleCreateFeedback,
220+
onReturnItem: handleReturnItem,
221+
onPublishFeedback: handlePublishFeedback,
222+
onRefundPurchase: handleRefundPurchases,
223+
onEditPurchase: handleEditPurchase,
224+
onGenerateLink: handleGenerateLink,
225+
onSetScreenshot: setScreenshot,
226+
onCreateNewPurchase: () => setCreateNewPurchase(true),
227+
});
228+
243229
return (
244230
<DefaultLayout>
245231
<section
@@ -257,138 +243,7 @@ export default function IndexPage() {
257243
) : (
258244
<div className="flex gap-3 max-w-screen">
259245
<PaginatedTable
260-
columns={[
261-
{
262-
field: "purchase",
263-
label: t("purchase"),
264-
sortable: false,
265-
cellCopyable: true,
266-
className: "hidden md:table-cell",
267-
headerClassName: "hidden md:table-cell",
268-
render: (item: PurchaseStatus) => (
269-
<PurchaseIdCell
270-
purchaseId={item.purchase}
271-
hasPublication={item.hasPublication}
272-
onEditPurchase={handleEditPurchase}
273-
onGenerateLink={handleGenerateLink}
274-
/>
275-
),
276-
},
277-
{
278-
field: "date",
279-
label: t("date"),
280-
sortable: true,
281-
className: "hidden md:table-cell",
282-
headerClassName: "hidden md:table-cell",
283-
},
284-
{
285-
field: "order",
286-
label: t("order"),
287-
sortable: true,
288-
className: "hidden md:table-cell",
289-
headerClassName: "hidden md:table-cell",
290-
render: (item: PurchaseStatus) => {
291-
return (
292-
<>
293-
<Link
294-
className="text-blue-500 hover:underline break-keep"
295-
target="_blank"
296-
to={`${import.meta.env.AMAZON_BASE_URL}${item.order}`}
297-
>
298-
{cleanAmazonOrderNumber(item.order)}
299-
</Link>
300-
<CopyButton
301-
className="absolute top-0 right-0"
302-
value={item.order}
303-
/>
304-
</>
305-
);
306-
},
307-
},
308-
{
309-
field: "description",
310-
label: t("description"),
311-
sortable: false,
312-
render: (item: PurchaseStatus) => (
313-
<StatusCell
314-
text={item.description}
315-
screenshot={item.purchaseScreenshot}
316-
screenshotSummary={item.screenshotSummary}
317-
copyTooltipKey="copy-screenshots"
318-
onScreenshotClick={setScreenshot}
319-
/>
320-
),
321-
onCellAction: (item: PurchaseStatus) => {
322-
item.screenshotSummary
323-
? setScreenshot([
324-
item.purchaseScreenshot || Transparent1x1WebpPixel,
325-
item.screenshotSummary,
326-
])
327-
: setScreenshot(item.purchaseScreenshot || Transparent1x1WebpPixel);
328-
},
329-
},
330-
{
331-
field: "amount",
332-
label: t("amount"),
333-
sortable: false,
334-
className: "hidden md:table-cell",
335-
headerClassName: "hidden md:table-cell",
336-
},
337-
{
338-
field: "hasFeedback",
339-
label: t("hasFeedback"),
340-
sortable: false,
341-
className: "hidden md:table-cell",
342-
headerClassName: "hidden md:table-cell",
343-
},
344-
{
345-
field: "hasPublication",
346-
label: t("hasPublication"),
347-
sortable: false,
348-
className: "hidden md:table-cell",
349-
headerClassName: "hidden md:table-cell",
350-
render: (item: PurchaseStatus) => (
351-
<StatusCell
352-
text={item.hasPublication ? t("yes") : t("no")}
353-
screenshot={item.publicationScreenshot}
354-
copyTooltipKey="copy-screenshot"
355-
onScreenshotClick={(screenshot) => setScreenshot(screenshot)}
356-
/>
357-
),
358-
onCellAction: (item) => {
359-
if (item.hasPublication) {
360-
setScreenshot(item.publicationScreenshot);
361-
}
362-
},
363-
},
364-
{
365-
field: "refunded",
366-
label: t("refunded"),
367-
sortable: false,
368-
className: "hidden md:table-cell",
369-
headerClassName: "hidden md:table-cell",
370-
render: (item: PurchaseStatus) => {
371-
return item.refunded ? (
372-
<>
373-
{item.transactionId && item.transactionId.length >= 4 && !item.transactionId.startsWith("REFUND_") ? (
374-
<Link
375-
className="text-blue-500 hover:underline break-keep"
376-
target="_blank"
377-
to={`${import.meta.env.PAYPAL_TRANSACTION_BASE_URL}${item.transactionId}`}>{t("yes")}
378-
</Link>
379-
) : (
380-
<span>{t("yes")}</span>
381-
)}
382-
</>) :
383-
<>{t("no")}</>;
384-
}
385-
},
386-
{
387-
field: "actions",
388-
label: t("actions"),
389-
render: (item) => renderActionColumn(item),
390-
},
391-
]}
246+
columns={columns}
392247
dataUrl={`${import.meta.env.API_BASE_URL}/purchase-status?limitToNotRefunded=${toggleAllPurchases ? "false" : "true"}`}
393248
manualData={searchResults.length > 0 ? searchData : undefined}
394249
manualIsLoading={searchDataLoading}
@@ -399,22 +254,7 @@ export default function IndexPage() {
399254
refreshTrigger={refreshTrigger}
400255
rowKey="purchase"
401256
title={getTitleComponent}
402-
emptyContent={
403-
<div className="text-center text-muted-foreground p-4">
404-
{t("no-data-available")}
405-
{hasWritePermission && (
406-
<div className="mt-4">
407-
<Button
408-
color="primary"
409-
startContent={<EditIcon />}
410-
onPress={() => setCreateNewPurchase(true)}
411-
>
412-
{t("new-purchase")}
413-
</Button>
414-
</div>
415-
)}
416-
</div>
417-
}
257+
emptyContent={emptyContent}
418258
/>
419259
</div>
420260
)}

0 commit comments

Comments
 (0)