Agent Skill
2/7/2026

frontend-development

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.

D
ducnm
0GitHub Stars
1Views
npx skills add ducnm-mimhus/Avada-Simple-Sales-Pop

SKILL.md

Namefrontend-development
DescriptionUse 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.

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):

// 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

yarn update-label

Step 3: Use in components

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

{
  "pointsEarned": "You earned {points} points!",
  "welcome": "Welcome, {name}!"
}
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
// loadables/CustomerPage/index.js
export default Loadable({
  loader: () => import('../../pages/Customer'),
  loading: CustomerSkeleton
});

Skeleton Loading

All data-fetching pages must have skeleton loading states:

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

API Hooks

Fetch Data

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

Create/Update

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

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

Delete

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

// Usage
await handleDelete(customerId);

Edit (Update)

const {editing, handleEdit} = useEditApi({
  url: `/api/customers/${customerId}`,
  successMsg: 'Customer updated successfully',
  successCallback: () => fetchApi()
});

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

Save Bar (App Bridge)

The <ui-save-bar> web component requires refs and setAttribute for loading state (React props don't work on web components).

Pattern

import {useRef, useEffect} from 'react';
import {useAppBridge} from '@shopify/app-bridge-react';

function MyForm() {
  const shopify = useAppBridge();
  const saveButtonRef = useRef(null);
  const [isDirty, setIsDirty] = useState(false);
  const [saving, setSaving] = useState(false);

  // Show/hide save bar based on form changes
  useEffect(() => {
    if (isDirty) {
      shopify.saveBar.show('my-save-bar');
    } else {
      shopify.saveBar.hide('my-save-bar');
    }
  }, [isDirty, shopify]);

  // Set loading state on save button (CRITICAL: use setAttribute)
  useEffect(() => {
    if (saveButtonRef.current) {
      if (saving) {
        saveButtonRef.current.setAttribute('loading', '');
        saveButtonRef.current.setAttribute('disabled', '');
      } else {
        saveButtonRef.current.removeAttribute('loading');
        saveButtonRef.current.removeAttribute('disabled');
      }
    }
  }, [saving]);

  const handleSave = async () => {
    setSaving(true);
    await saveData();
    setSaving(false);
    setIsDirty(false);
  };

  const handleDiscard = () => {
    resetForm();
    setIsDirty(false);
  };

  return (
    <Page title="Settings">
      <ui-save-bar id="my-save-bar">
        <button ref={saveButtonRef} variant="primary" onClick={handleSave}>
          Save
        </button>
        <button onClick={handleDiscard}>Discard</button>
      </ui-save-bar>
      {/* Form content */}
    </Page>
  );
}

Key Points

IssueSolution
Loading state not workingUse setAttribute('loading', '') via ref
Disabled state not workingUse setAttribute('disabled', '') via ref
Save bar not showingCall shopify.saveBar.show('bar-id')
Save bar not hidingCall shopify.saveBar.hide('bar-id')

Resource Picker (App Bridge)

Use App Bridge's resource picker for selecting Shopify resources (products, collections, etc.).

Product Selection

import {useAppBridge} from '@shopify/app-bridge-react';

function ProductSelector({selectedProducts, onSelect}) {
  const shopify = useAppBridge();

  const handleSelectProducts = async () => {
    try {
      const selected = await shopify.resourcePicker({
        type: 'product',
        multiple: true,
        selectionIds: selectedProducts.map(p => ({id: p.id})),
        filter: {
          variants: false  // Exclude variants
        }
      });

      if (selected) {
        onSelect(selected.map(product => ({
          id: product.id,
          title: product.title,
          image: product.images?.[0]?.originalSrc || null
        })));
      }
    } catch (error) {
      console.error('Resource picker error:', error);
    }
  };

  return (
    <Button icon={SearchIcon} onClick={handleSelectProducts}>
      Browse products
    </Button>
  );
}

Resource Picker Options

OptionTypeDescription
typestring'product', 'collection', 'variant'
multiplebooleanAllow multiple selection
selectionIdsarrayPre-selected resource IDs [{id: 'gid://...'}]
filter.variantsbooleanInclude/exclude variants
filter.draftbooleanInclude draft products

State Management

  • Use React Context for global state
  • Use local state for component-specific data
  • Use Redux Saga sparingly (legacy patterns)
// 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

# 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
Skills Info
Original Name:frontend-developmentAuthor:ducnm