Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
26e756a
[CCUBE-2188][GZ] extract shared utils, define new types
ghazwanmuhammad Aug 17, 2026
03965dc
[CCUBE-2188][GZ] merge file list item and file item edit
ghazwanmuhammad Aug 17, 2026
4ee9ba9
[CCUBE-2188][GZ] merge styles
ghazwanmuhammad Aug 17, 2026
3d27231
[CCUBE-2188][GZ] internalize mode management
ghazwanmuhammad Aug 17, 2026
01f577d
[CCUBE-2188][GZ] update error styling
ghazwanmuhammad Aug 17, 2026
ecd3d1d
[CCUBE-2188][GZ] simplify render item fn
ghazwanmuhammad Aug 19, 2026
3f99a12
[CCUBE-2188][GZ] remove grouping logic
ghazwanmuhammad Aug 25, 2026
b3ca064
[CCUBE-2188][GZ] extract styling to component style file
ghazwanmuhammad Aug 25, 2026
93a9327
[CCUBE-2188][GZ] remove description render on error
ghazwanmuhammad Aug 25, 2026
7fdebb2
[CCUBE-2188][GZ] remove unnecessary lines on file item details
ghazwanmuhammad Aug 25, 2026
72bc9e7
[CCUBE-2188][GZ] inline actions
ghazwanmuhammad Aug 25, 2026
8201703
[CCUBE-2188][GZ] restore comments
ghazwanmuhammad Aug 25, 2026
dd5984a
[CCUBE-2188][GZ] simplified parent child interaction
ghazwanmuhammad Aug 25, 2026
5061f9e
[CCUBE-2188][GZ] improve file list item
ghazwanmuhammad Aug 25, 2026
6422291
[CCUBE-2188][GZ] remove desktop long desc snapshot
ghazwanmuhammad Aug 25, 2026
ac42019
[CCUBE-2188][GZ] bring back disable sort when any item is on edit mode
ghazwanmuhammad Aug 26, 2026
623de02
[CCUBE-2188][GZ] consider description only when required
ghazwanmuhammad Aug 28, 2026
03b4128
[CCUBE-2188][GZ] move derived state position
ghazwanmuhammad Aug 28, 2026
68cda4f
[CCUBE-2188][GZ] vertically center image when no inline actions present
ghazwanmuhammad Aug 28, 2026
f4feebc
[CCUBE-2188][GZ] handles when file list items changed on edit mode
ghazwanmuhammad Aug 28, 2026
2b30da4
[CCUBE-2188][GZ] fix item not entering edit mode
ghazwanmuhammad Aug 28, 2026
e70eed0
[CCUBE-2188][GZ] fix mismatch state between parent and child
ghazwanmuhammad Sep 8, 2026
3ba544e
[CCUBE-2188][GZ] move sort test from e2e to ut
ghazwanmuhammad Sep 16, 2026
4adea55
[CCUBE-2188][GZ] refactor edit behavior
ghazwanmuhammad Sep 16, 2026
7333051
[CCUBE-2188][GZ] fix edit behavior on mount
ghazwanmuhammad Sep 16, 2026
ae3c79e
[MOL-2188][GZ] remove descriptionRequired gate for onModeChange on mount
ghazwanmuhammad Sep 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 47 additions & 16 deletions e2e/nextjs-app/src/app/components/file-upload/editable.e2e.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,80 @@

import type { FileItemProps } from "@lifesg/react-design-system/file-upload";
import { FileUpload } from "@lifesg/react-design-system/file-upload";
import { useState } from "react";
import { useRef, useState } from "react";

const THUMBNAIL_URL = "/sample.jpg";

const INITIAL_ITEMS: FileItemProps[] = [
{
id: "editable-image",
name: "editable-image.jpg",
size: 5120,
type: "image/jpeg",
thumbnailImageDataUrl: "/sample.jpg",
thumbnailImageDataUrl: THUMBNAIL_URL,
},
{
id: "described-image",
name: "described-image.jpg",
size: 3072,
type: "image/jpeg",
thumbnailImageDataUrl: THUMBNAIL_URL,
description: "Already has a description",
},
{
id: "another-image",
name: "another-image.jpg",
size: 2048,
type: "image/jpeg",
thumbnailImageDataUrl: THUMBNAIL_URL,
description: "Another described image",
},
];

export default function Story() {
const nextId = useRef(0);
const [fileItems, setFileItems] = useState<FileItemProps[]>(INITIAL_ITEMS);

const handleEdit = (updatedItem: FileItemProps) => {
setFileItems((prevItems) => {
return prevItems.map((item) => {
if (item.id === updatedItem.id) {
return updatedItem;
}

return item;
});
const handleChange = (files: File[]) => {
const newItems = files.map((file) => {
nextId.current += 1;
return {
id: `upload-file-${nextId.current}`,
name: file.name,
size: file.size,
type: file.type,
};
});
setFileItems((prev) => prev.concat(newItems));
};

const handleEdit = (updatedItem: FileItemProps) => {
setFileItems((prevItems) =>
prevItems.map((item) =>
item.id === updatedItem.id ? updatedItem : item
)
);
};

const handleDelete = (deletedItem: FileItemProps) => {
setFileItems((prevItems) => {
return prevItems.filter((item) => item.id !== deletedItem.id);
});
setFileItems((prevItems) =>
prevItems.filter((item) => item.id !== deletedItem.id)
);
};

return (
<FileUpload
data-testid="file-upload"
title="Editable file items"
description="Add a description, save it, and reopen edit mode."
title="Editable and sortable file items"
description="Add a description, save it, and reopen edit mode. Sort is disabled while any item is in edit mode."
fileItems={fileItems}
editableFileItems
sortable
fileDescriptionMaxLength={200}
onChange={handleChange}
onEdit={handleEdit}
onDelete={handleDelete}
onSort={setFileItems}
/>
);
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 30 additions & 1 deletion e2e/tests/components/file-upload/file-upload.e2e.spec.ts
Comment thread
qroll marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -328,9 +328,21 @@ test.describe("FileUpload", () => {
story.locators.internal.editDisplay("editable-image")
).toBeVisible();

const dragHandle = story.locators.fileUpload.locator(
'[data-testid$="-drag-handle"]'
);
await expect(dragHandle).toHaveCount(0);

await compareScreenshot(story, "mount");
});

await test.step("Sort disabled while an item is in edit mode", async () => {
const dragHandle = story.locators.fileUpload.locator(
'[data-testid$="-drag-handle"]'
);
await expect(dragHandle).toHaveCount(0);
});

await test.step("Save description", async () => {
await story.locators.internal
.textarea("editable-image")
Expand All @@ -350,10 +362,20 @@ test.describe("FileUpload", () => {
});
});

await test.step("Sort enabled after all items in display mode", async () => {
const dragHandle = story.locators.fileUpload.locator(
'[data-testid$="-drag-handle"]'
);
await expect(dragHandle.first()).toBeVisible();
});

await test.step("Cancel edit keeps saved description", async () => {
await story.locators.internal
.editButton("editable-image")
.click();
await expect(
story.locators.internal.textarea("editable-image")
).toBeVisible();
await story.locators.internal
.textarea("editable-image")
.fill("Temporary change");
Expand All @@ -367,6 +389,13 @@ test.describe("FileUpload", () => {
)
).toBeVisible();
});

await test.step("Sort restored after cancel", async () => {
const dragHandle = story.locators.fileUpload.locator(
'[data-testid$="-drag-handle"]'
);
await expect(dragHandle.first()).toBeVisible();
});
});
});

Expand Down Expand Up @@ -467,7 +496,7 @@ test.describe("FileUpload", () => {
await story.init("long-description", { size: "mobile" });
});

test("Long description text", async ({ story }) => {
test("Long description text - mobile", async ({ story }) => {
await compareScreenshot(story, "mount", {
locator: story.locators.fileUpload,
});
Expand Down
91 changes: 0 additions & 91 deletions src/file-upload/file-item-edit.styles.ts

This file was deleted.

Loading
Loading