Skip to main content

Example App | Create, Read, Update, and Delete Users

This example show cases a simple, but powerful, user management tool that can view, edit, create, and delete users (a.k.a. a CRUD app!).

CRUD operations are the basis for many internal tools, and the patterns used here can be easily extended to all kinds of data and use cases.

Use the app

You can use this app yourself! Here's the link.

Code Reference

import { Compose, Page, UI } from "@composehq/sdk";

interface User {
id: number;
name: string;
email: string;
confirmedEmail: boolean;
}

// This is a fake list of users. In a real app, you'd likely be using a database.
const dbUsers: User[] = [
{ id: 1, name: "John Doe", email: "john.doe@example.com", confirmedEmail: true },
{ id: 2, name: "Jane Smith", email: "jane.smith@example.com", confirmedEmail: false },
{ id: 3, name: "Bob Johnson", email: "bob.johnson@example.com", confirmedEmail: true },
{ id: 4, name: "Alice Brown", email: "alice.brown@example.com", confirmedEmail: true },
{ id: 5, name: "Charlie Wilson", email: "charlie.wilson@example.com", confirmedEmail: false },
{ id: 6, name: "Eva Green", email: "eva.green@example.com", confirmedEmail: true },
{ id: 7, name: "David Lee", email: "david.lee@example.com", confirmedEmail: false },
{ id: 8, name: "Fiona White", email: "fiona.white@example.com", confirmedEmail: true },
{ id: 9, name: "George Black", email: "george.black@example.com", confirmedEmail: true },
{ id: 10, name: "Helen Gray", email: "helen.gray@example.com", confirmedEmail: false },
];

function handler({
page,
ui,
}: {
page: Page;
ui: UI;
}) {
// Simulate a db query to fetch users.
let users: User[] = [...dbUsers];

// Add a page header
page.add(() =>
ui.stack([
ui.header("Users Dashboard"),
ui.text("This is a demo!"),
])
);

async function deleteUser(user: User) {
const confirmed = await page.confirm({
title: "Delete User",
message: "Are you sure you want to delete this user?",
typeToConfirmText: user.name,
});

if (confirmed) {
users = users.filter((u) => u.id !== user.id);
page.update();
page.toast("User deleted successfully!", { appearance: "success" });
}
}

async function editUser(user: User, idx: number) {
page.modal(
({ resolve }) => ui.form(
"edit-user-form",
[
ui.textInput("name", { initialValue: user.name }),
ui.emailInput("email", { initialValue: user.email }),
ui.checkbox("confirmedEmail", { initialValue: user.confirmedEmail }),
],
{
onSubmit: (formData) => {
users[idx] = { ...users[idx], ...formData };
page.update();
page.toast("User updated successfully!", { appearance: "success" });

// Close the modal
resolve();
},
}
),
{ title: "Edit User" }
);
}

async function createUser() {
page.modal(
({ resolve }) => ui.form(
"create-user-form",
[
ui.textInput("name"),
ui.emailInput("email"),
ui.checkbox("confirmedEmail"),
],
{
onSubmit: (formData) => {
const newUser = {
id: users.length + 1,
name: formData.name,
email: formData.email,
confirmedEmail: formData.confirmedEmail,
};

users.push(newUser);
page.update();
page.toast("User created successfully!", { appearance: "success" });

// Close the modal
resolve();
},
}
),
{ title: "Create User" }
);
}

// Show a table of users. Each row has an "Edit" and "Delete" button.
// and there's a "Create User" button above the table.
page.add(() => ui.stack([
ui.distributedRow([
ui.header("Users", { size: "sm" }),
ui.button("create-user", {
onClick: createUser,
}),
]),
ui.table("users-table", users, {
columns: ["name", "email", "confirmedEmail"],
actions: [
{
label: "Edit",
onClick: editUser,
surface: true,
},
{
label: "Delete",
onClick: deleteUser,
surface: true,
},
],
}),
]));
}

const crudApp = new Compose.App({
name: "CRUD App",
route: "crud-app",
handler,
});