Files
artcraft-services/frontend
BFlatandClaude Opus 5.5 3880127f68 Add Google Analytics to the marketing site (#50)
## What

Adds GA4 to `artcraft-website-next`, covering the whole marketing site.

- `src/components/analytics.tsx` loads gtag.js (`afterInteractive`) and
installs one delegated click listener. It's mounted once in the root
layout.
- `src/lib/analytics.ts` holds the typed event catalogue,
`trackEvent()`, `trackAttrs()` (data attributes that work in server
components) and the link classifier.
- Analytics is **off unless `NEXT_PUBLIC_GA_MEASUREMENT_ID` is set**, so
local dev and deploy previews stay out of the reports.

## Why

The new site had no analytics. This gives us download, signup and
checkout funnels, plus CTA performance by page section.

## Events

GA4 Enhanced Measurement handles page views (App Router history
changes), scrolls, outbound clicks and common file downloads. On top of
that:

| Event | Trigger |
|---|---|
| `app_download` | GitHub release asset clicks (ArtCraft + Crafting
Apps): app, version, platform, file |
| `webapp_click` | Links to app.getartcraft.com: destination path |
| `cta_click` | Other `Button` links (tagged `data-cta`) |
| `app_select` | App cards and icons on `/apps` and sibling cards on app
pages: app name |
| `social_click`, `contact_click` | `SOCIAL_LINKS` hosts, mailto / copy
email |
| `begin_checkout` | Plan selection (`signup`/`subscribe`/`switch`) and
credit packs, with GA4 ecommerce `items` |
| `billing_cadence_change`, `view_credit_packs`, `manage_subscription` |
Pricing actions |
| `prompt_submit`, `video_generation` | H3 promptbox (`logged_in`;
complete/failed/timeout) |
| `sign_up`, `login` | Auth gate success |
| `generate_lead` | Beta form submission (honeypot hits excluded) |
| `video_start`, `share`, `copy_command`, `copy_prompt`,
`media_download`, `press_kit_download` | Video facades, share bars, copy
buttons, media/press downloads |

Every delegated click event also carries `link_location`: nav, footer,
modal, or the enclosing `section[id]`.

## Reviewer notes

- `Button` now renders `data-cta=""` on its anchor variants. There is no
visual change.
- `PricingTable.choosePlan` now branches on the computed `checkoutType`
rather than repeating the `user`/`hasActivePlan` conditions. The
behaviour is unchanged.
- `AuthGateModal` forms now return early on error instead of using
if/else, so the success event goes on the success path.

## Deploy

Set `NEXT_PUBLIC_GA_MEASUREMENT_ID` in Netlify, **Production context
only**, then redeploy. The ID is inlined at build time. This is
documented in `netlify.toml`.

After deploying:
- Mark key events in GA: `app_download`, `begin_checkout`, `sign_up`,
`generate_lead`, `webapp_click`.
- Register custom dimensions (e.g. `link_location`, `app_name`,
`platform`, `destination`, `checkout_type`) so the params show in
reports.

## Testing

Ran the dev server with a dummy measurement ID and checked `dataLayer`
on these pages:
- `/`: nav, footer, CTA, social, mailto and YouTube events.
- `/download`: Windows and macOS installers.
- `/apps/photocraft`: Linux downloads, share, copy command, GitHub link,
and `app_select` on the sibling cards (also checked on the `/apps` icon
row and lineup cards).
- `/pricing`: cadence toggle.
- `/minimax-h3`: logged-out `prompt_submit` and example `video_start`.

Not exercised in the browser: the beta form (submitting would post a
real Google Form entry), signup/login, checkout, the credits modal, the
media page, the press kit, email copy and manage plan.

`tsc` shows no new errors. Existing errors in `media-viewer-3d.tsx` and
the Playwright test files are unchanged. The production build was not
run.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 20:00:50 +07:00
..
2026-03-12 15:49:24 +07:00
wip
2026-09-14 15:40:33 -04:00

Frontend

This is the Nx workspace for ArtCraft web apps and shared libraries. The desktop frontend is maintained in storytold/artcraft.

All commands to run these projects are performed from this directory (except the repo-root launcher scripts noted below).

Requirements

  • Node.js 20+ (Nx 21 / Vite 6 requirement). Install via nvm, nodejs.org, or brew install node.
  • npm (ships with Node).

We use npm, not pnpm. pnpm was briefly adopted ("add pnpm to solve build issues") and later removed ("fix(frontend): consume video-editor libs via nx path aliases, drop pnpm"). If you have leftovers from that era — a pnpm-lock.yaml, pnpm-workspace.yaml, or a node_modules/.pnpm directory — npm installs will fail (typically with ENOTEMPTY rename errors). See Troubleshooting below.

Install dependencies

npm install

Running the apps in dev mode

From the repository root, the launcher scripts (these preflight your environment, install dependencies, and free the dev port first):

./script/website/unix_frontend_website_dev.sh  # artcraft-website (marketing site), port 4200
./script/website/unix_frontend_webapp_dev.sh   # artcraft-webapp (user dashboard), port 4201

Run the webapp from artcraft-services, not the separate artcraft desktop checkout. The webapp launcher also works from another directory when invoked by its full or relative path:

../artcraft-services/script/website/unix_frontend_webapp_dev.sh

Or directly from this directory:

nx dev artcraft-website
npx nx dev @frontend/artcraft-webapp

Building

npx nx build artcraft-website
npx nx build artcraft-webapp

Netlify deploys run apps/<app>/script/netlify_build.sh (see each app's netlify.toml).

Troubleshooting

npm install fails with ENOTEMPTY: directory not empty, rename ...

Your node_modules tree is corrupted — usually an interrupted install, or a tree written by pnpm back when the repo briefly used it. Fix:

./clean_modules.sh
npm install

Or the manual minimum:

rm -rf node_modules .nx pnpm-lock.yaml pnpm-workspace.yaml
npm install

Stale build state after switching branches

Call this when starting on main or a new branch:

./clean_modules.sh

It removes all dist/ outputs, resets the nx cache, and removes node_modules.

Import aliases

The names for @frontend and @storyteller come from the package.json file in the libs folder:

import { Login } from "@frontend/login";
import { api } from "@storyteller/api";

For shared UI components, import from @storyteller/ui-[componentname]:

import { Button } from "@storyteller/ui-button";
import { Modal } from "@storyteller/ui-modal";

Generating a new component library

# 1. Generate the library
npx nx g @nx/react:library libs/components/toaster --import-path=@storyteller/ui-toaster --bundler=vite
npm install

# 2. Import it somewhere in code

# 3. Sync and build
nx sync
nx build