home / skills / trantuananh-17 / product-reviews / frontend

frontend skill

/.claude/skills/frontend

This skill provides React and Polaris patterns for admin frontends, including translations, skeleton loading, and loadable components to accelerate UI

npx playbooks add skill trantuananh-17/product-reviews --skill frontend

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
4.4 KB
---
name: frontend-development
description: Use this skill when the user asks about "React admin", "Polaris pages", "translations", "loadable components", "skeleton loading", "useFetchApi", "useCreateApi", "locale", "i18n", or any admin frontend development work. Provides React/Polaris patterns for the embedded admin app.
---

# Frontend Development (packages/assets)

> **Admin Embedded App** - Uses React + Shopify Polaris
>
> For **storefront widgets** (customer-facing), see `scripttag` skill

## Directory Structure

```
packages/assets/src/
├── components/        # Reusable React components
├── pages/            # Page components with skeleton loading
├── loadables/        # Code-split components (organized in folders)
├── contexts/         # React contexts for state management
├── hooks/            # Custom React hooks (API, state)
├── services/         # API services calling admin endpoints
├── routes/           # Route definitions (routes.js)
└── locale/           # Translations
    ├── input/        # Source translation JSON files
    └── output/       # Generated translated files
```

---

## Translations

### Overview

The app supports multiple languages (en, fr, es, de, it, ja, id, uk). Translation keys are defined in JSON files in `packages/assets/src/locale/input/`, then auto-translated to all supported languages.

### Adding/Updating Translation Keys

**Step 1: Edit or create JSON file in `locale/input/`**

Files are named after components/features (PascalCase):

```json
// locale/input/Activity.json
{
  "title": "Activities",
  "subtitle": "Manage your customers' loyalty activities in one place",
  "learnMore": "Learn more",
  "pointTab": "Point Activities"
}
```

**Step 2: Run the translation script**

```bash
yarn update-label
```

**Step 3: Use in components**

```javascript
import {useTranslation} from 'react-i18next';

function ActivityPage() {
  const {t} = useTranslation();

  return (
    <Page title={t('Activity.title')}>
      <Text>{t('Activity.subtitle')}</Text>
    </Page>
  );
}
```

### Variables in Translations

```json
{
  "pointsEarned": "You earned {points} points!",
  "welcome": "Welcome, {name}!"
}
```

```javascript
t('Reward.pointsEarned', { points: 100 })
// Output: "You earned 100 points!"
```

---

## Component Guidelines

### File Extensions
- Use `.js` files only (no `.jsx`)

### Loadable Components
- Always create in organized folders with `index.js`
- Never create loadable components at top level

```javascript
// loadables/CustomerPage/index.js
export default Loadable({
  loader: () => import('../../pages/Customer'),
  loading: CustomerSkeleton
});
```

### Skeleton Loading

All data-fetching pages must have skeleton loading states:

```javascript
function CustomerPageSkeleton() {
  return (
    <SkeletonPage primaryAction>
      <Layout>
        <Layout.Section>
          <Card>
            <SkeletonBodyText lines={5} />
          </Card>
        </Layout.Section>
      </Layout>
    </SkeletonPage>
  );
}
```

---

## API Hooks

### Fetch Data

```javascript
const {data, loading, fetchApi} = useFetchApi({
  url: '/api/customers',
  defaultData: [],
  initLoad: true  // Load on mount
});
```

### Create/Update

```javascript
const {creating, handleCreate} = useCreateApi({
  url: '/api/customers',
  successMsg: 'Customer created successfully',
  successCallback: () => fetchApi()
});

// Usage
await handleCreate({ name, email, points });
```

### Delete

```javascript
const {deleting, handleDelete} = useDeleteApi({
  url: '/api/customers',
  successMsg: 'Customer deleted',
  successCallback: () => fetchApi()
});

// Usage
await handleDelete(customerId);
```

---

## State Management

- Use React Context for global state
- Use local state for component-specific data
- Use Redux Saga sparingly (legacy patterns)

```javascript
// contexts/ShopContext.js
const ShopContext = createContext();

export function ShopProvider({ children }) {
  const [shop, setShop] = useState(null);

  return (
    <ShopContext.Provider value={{ shop, setShop }}>
      {children}
    </ShopContext.Provider>
  );
}

export const useShop = () => useContext(ShopContext);
```

---

## Development Commands

```bash
# Start embedded app development
cd packages/assets && npm run watch:embed

# Start standalone development
cd packages/assets && npm run watch:standalone

# Production build
cd packages/assets && npm run production
```

Overview

This skill provides practical React + Shopify Polaris patterns for building an embedded admin app. It covers translations, code-splitting with loadable components, skeleton loading states, API hooks (fetch/create/delete), and context-based state. Use it to standardize admin pages and developer workflows for the admin frontend.

How this skill works

The skill inspects common admin needs and recommends component structure, translation workflows, and API hook usage. It enforces code-splitting by organizing loadable components in folders, requires skeleton pages for all data-fetching routes, and promotes lightweight contexts for global state. It also outlines translation key formats and commands to update localized files.

When to use it

  • Creating or updating admin pages that use Shopify Polaris UI
  • Implementing translations and multi-locale support
  • Adding code-splitting for large pages with Loadable components
  • Building data-driven pages that require skeleton loading states
  • Using standardized API hooks for fetch/create/delete operations

Best practices

  • Keep components in packages/assets/src/components and pages in pages/ with skeleton counterparts
  • Place loadable components in dedicated folders with index.js; never create loadables at the top level
  • Always provide a SkeletonPage for pages that fetch data to avoid layout shifts
  • Define translation keys in locale/input as JSON per feature and run the translation script to generate locales
  • Use React Context for lightweight global state and local component state for UI concerns
  • Use useFetchApi, useCreateApi, and useDeleteApi for consistent API interactions and success callbacks

Example use cases

  • Add a Customer page: create a page component, a Loadable wrapper, and a CustomerPageSkeleton to display while fetching
  • Add a new translation: add a JSON file in locale/input, run the translation update command, then use t('Feature.key') in components
  • Implement create flow: use useCreateApi with a successCallback to refresh the listing via useFetchApi
  • Code-split a heavy report page by moving it to loadables/ReportPage with an index.js loader
  • Manage shop-level settings with a ShopContext provider and useShop hook for cross-page access

FAQ

How do I use variables inside translation strings?

Include placeholders like {name} or {points} in the JSON and pass values with t('Key', { name: 'Alex', points: 100 }).

When should I create a Loadable component?

Create a Loadable for any page or component that significantly increases bundle size or is not needed on initial load; organize it in its own folder with index.js.