Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -618,3 +618,11 @@ import type {
## License

MIT

## Skill install (skills.sh)

Want to reuse this SDK as a Codex/skills.sh skill? The skill lives at `skills/appgram-react-native-sdk`.

- Local install from this repo: `npx skills add . --skill appgram-react-native-sdk`
- From GitHub: `npx skills add https://github.com/<owner>/<repo> --skill appgram-react-native-sdk`
- Peer deps required in consuming projects: `@react-native-async-storage/async-storage`, `lucide-react-native`, `react-native-svg`, `react-native-markdown-display`, `react-native-render-html` (install after `@appgram/react-native`; run `npx pod-install` for iOS).
14 changes: 14 additions & 0 deletions skills/appgram-react-native-sdk/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Appgram React Native SDK skill (skills.sh)

Use this to pull the SDK guidance into Codex/skills.sh.

Install:
- From this repo root: `npx skills add . --skill appgram-react-native-sdk`
- From GitHub: `npx skills add https://github.com/<owner>/<repo> --skill appgram-react-native-sdk`

What’s inside:
- `SKILL.md` instructions for integrating/maintaining `@appgram/react-native`
- `agents/openai.yaml` display metadata
- references for hooks, components, API client, platform setup, and snippets

Peer deps (for app integrators): `@react-native-async-storage/async-storage`, `lucide-react-native`, `react-native-svg`, `react-native-markdown-display`, `react-native-render-html` (run `npx pod-install` on iOS after installing).
109 changes: 109 additions & 0 deletions skills/appgram-react-native-sdk/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
---
name: appgram-react-native-sdk
description: "Integrate or maintain the Appgram React Native SDK (@appgram/react-native): install peers, configure AppgramProvider, use built-in components/hooks for feedback, roadmap, releases, help center, support, surveys, blog, status, chat, apply theming, and run build/lint/docs tasks."
---

# Appgram React Native SDK

## When to use
- You need to embed Appgram feedback/roadmap/changelog/help/support/surveys/blog/status/chat in a React Native app.
- You are wiring Appgram headless hooks into custom UI.
- You are maintaining this SDK: build, lint, docs, publish, or debugging peer/native issues.

## Prerequisites
- React Native ≥0.70, React 18, Metro; iOS requires CocoaPods, Android uses autolinking.
- Peer deps: `@react-native-async-storage/async-storage`, `lucide-react-native`, `react-native-svg`, `react-native-markdown-display`, `react-native-render-html`.
- Install peers after the SDK, then `npx pod-install` for iOS.

## Quick start
- Install: `npm install @appgram/react-native` then peer deps `npm install @react-native-async-storage/async-storage lucide-react-native react-native-svg react-native-markdown-display react-native-render-html`.
- iOS: run `npx pod-install` after installing peers.
- Wrap your app once:
```tsx
<AppgramProvider config={{ projectId: 'YOUR_PROJECT_ID', orgSlug: 'org', projectSlug: 'project', apiUrl: 'https://api.appgram.dev', theme: { mode: 'system' } }}>
{children}
</AppgramProvider>
```
- Use ready UI or headless hooks:
```tsx
<WishList onWishPress={(wish) => console.log(wish)} />
<SupportForm onSuccess={() => Alert.alert('Sent')} />
// Hooks
const { wishes, isLoading, refetch } = useWishes()
const { vote } = useVote()
```

## Feature map (components → hooks)
- Feedback: `WishList`, `WishCard`, `VoteButton`, `WishDetailModal`, `SubmitWishSheet` → `useWishes`, `useVote`, `useComments`.
- Roadmap: `RoadmapBoard` → `useRoadmap`.
- Releases/Changelog: `Releases`, `ReleaseList`, `ReleaseDetail` → `useReleases`, `useRelease`.
- Help Center: `HelpCenter`, `HelpFlowCard`, `HelpFlowDetail`, `HelpArticleCard`, `HelpArticleDetail` → `useHelpCenter`, `useHelpFlow`, `useHelpArticle`.
- Support & Forms: `SupportForm`, `FormRenderer` → `useSupport`, `useForm`, `useFormSubmit`.
- Surveys: `SurveyForm` → `useSurvey`, `useSurveySubmit`.
- Blog: `Blog`, `BlogList`, `BlogCard`, `BlogPostDetail` → `useBlogPosts`, `useBlogPost`, `useBlogCategories`, `useFeaturedPosts`.
- Status: `StatusBoard` → `useStatus`.
- Chat: `ChatScreen` (`ChatSource` type available) – pull data via context client as needed.
- Base UI bits: `Button`, `Card`, `Badge`, `Input` for consistent styling.

**Hook pattern:** hooks return data + `isLoading` (and often `error`, `refetch`); many accept `refreshInterval` and filter props (see exported option/result types).

### Props & options details
- Hooks: see `references/hooks.md` (options, return shapes, behaviors like refreshInterval and fingerprinting).
- Components: see `references/components.md` (purpose + key props per component).

## Configuration & theming
- `AppgramProvider.config`:
- `projectId` (required), `orgSlug`/`projectSlug` for routing.
- `apiUrl` override for self-host/staging (default `https://api.appgram.dev`).
- `enableFingerprinting` (default true) uses AsyncStorage + device info for anonymous votes.
- `theme`: `mode` (`light`|`dark`|`system`), optional `lightColors`/`darkColors` partial overrides; defaults from Hazel design system.
- Access context: `useAppgramContext()` → `{ client, config, fingerprint, theme }`.
- Theming in custom UI: `useAppgramTheme()` → `{ colors, spacing, radius, typography, isDark, mode }`; palette exports `lightColors`, `darkColors`, scales `spacing`, `radius`, `typography` for reuse.

### Sample themed usage
```tsx
const { colors, spacing, radius } = useAppgramTheme()
return (
<Card style={{ backgroundColor: colors.background, padding: spacing.lg, borderRadius: radius.lg }}>
<WishList submitButtonText=\"Suggest a feature\" />
</Card>
)
```

## API client
- Get the instantiated `AppgramClient` from context: `const { client } = useAppgramContext()`.
- Methods mirror hooks (e.g., `client.getWishes`, `client.vote`, `client.getRoadmap`); responses follow `ApiResponse` / `PaginatedResponse` types exported from `types`.
- Use when you need imperative flows (e.g., prefetch before navigation) or custom caching.

## Local development & maintenance (this repo)
- Install dev deps: `npm install`.
- Lint: `npm run lint`; typecheck: `npm run typecheck`.
- Build package: `npm run build` (builder-bob, outputs to `lib/`); runs automatically on `npm install` via `prepare`.
- Docs: `npm run docs:json` (typedoc) → `docs.json`; `npm run docs:transform` (uses `transform-docs.js`); `npm run docs:build` to do both.
- Publish (when ready): `npm run release` (assumes npm auth + version bump). Keep `react-native-builder-bob` config in `package.json`; build uses `tsconfig.build.json`.

## Platform setup & debugging
- Install order, pod install, Gradle check, cache clears, and platform notes: `references/platform-setup.md`.

## Common recipes
- **Custom vote button:** use `useVote`; pass `onVote` to sync local counts; guard for missing fingerprint by showing a prompt to enable cookies/storage.
- **Support with magic link:** use `useSupport`; call `requestMagicLink(email)` then `verifyToken(token)`; tickets also saved locally (`storedTickets`, `clearStoredTickets`).
- **Embed changelog tab:** stack navigator screen with `Releases`; on press, navigate to detail screen wrapping `ReleaseDetail`.
- **Anonymous wishlist:** keep `enableFingerprinting` on (default); if privacy requires, set false and disable voting UI.
- **Blog index + detail:** `BlogList` for landing; use `useBlogPosts` if you need infinite scroll; route to `BlogPostDetail` on press.
- **Status page banner:** call `useStatus({ slug, refreshInterval: 60000 })` and render a small inline banner with `data.status`.
- See ready-to-paste code in `references/snippets.md`.

## Troubleshooting
- Missing peer deps / native linking: ensure all peers installed; run `npx pod-install` for iOS; clear Metro cache if symbols missing.
- Theming not applying: verify `theme.mode` not overridden by system; pass both light/dark overrides when customizing primary/background/foreground.
- Anonymous voting blocked: set `enableFingerprinting=false` if fingerprint cannot be generated, or ensure AsyncStorage works in environment.
- API errors: confirm `projectId`/slugs and `apiUrl`; use `client` methods to inspect `response.success` and `response.error`.
- Version support: built for React Native ≥0.70 and React 18+. Ensure `react-native-svg` and `lucide-react-native` versions stay compatible.

## References (load on demand)
- Hooks options/returns: `references/hooks.md`
- Components props notes: `references/components.md`
- API client methods + notes: `references/api-client.md`
- Platform setup & debugging: `references/platform-setup.md`
- Practical code snippets: `references/snippets.md`
4 changes: 4 additions & 0 deletions skills/appgram-react-native-sdk/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Appgram RN SDK"
short_description: "Use and maintain the Appgram React Native SDK."
default_prompt: "Use when integrating or maintaining @appgram/react-native: install peers, wrap AppgramProvider, pick components/hooks, theme overrides, and run lint/build/docs tasks."
65 changes: 65 additions & 0 deletions skills/appgram-react-native-sdk/references/api-client.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# AppgramClient reference (imperative API)

Get client: `const { client } = useAppgramContext()`. Methods return `ApiResponse<T>` unless noted.

## Wishes
- `getPublicWishes(filters?: WishFilters)` → paginated wishes (transforms raw response).
- `getWish(wishId)`
- `createWish({ title, description, author_email?, author_name?, category_id? })`

## Votes
- `checkVote(wishId, fingerprint)`
- `createVote(wishId, fingerprint, voterEmail?)`
- `deleteVote(voteId)`

## Comments
- `getComments(wishId, { page?, per_page? })` → normalizes to `CommentsResponse`.
- `createComment({ wish_id, content, author_name?, author_email?, parent_id? })`

## Roadmap
- `getRoadmapData()` (requires projectId; uses orgSlug/projectSlug when provided).

## Releases / Changelog
- Needs both `orgSlug` and `projectSlug` in provider config.
- `getReleases({ limit? })`
- `getRelease(releaseSlug)`
- `getReleaseFeatures(releaseSlug)`

## Help Center
- `getHelpCollection()` → `{ collection, flows }`
- `getHelpFlow(slug)`
- `getHelpArticle(slug, flowId)`

## Support
- `uploadFile(file)` → size limit 10MB; returns `{ url, name, size, mime_type? }`.
- `submitSupportRequest(data: SupportRequestInput)`; auto-uploads attachments first.
- `sendSupportMagicLink(email)`
- `verifySupportToken(token)` → `{ tickets, user_email }`
- `getSupportTicket(ticketId, token)`
- `addSupportMessage(ticketId, token, content)`

## Status
- `getPublicStatusOverview(slug = 'status')`

## Surveys
- `getPublicSurvey(slug)` → includes `nodes`.
- `submitSurveyResponse(surveyId, data)`
- `getPublicSurveyCustomization(surveyId)`

## Forms
- `getForm(formId)` → normalizes portal form shape.
- `trackFormView(formId)` → POST; tolerant of non-JSON responses.
- `submitForm(projectId, formId, data)` → tolerant of empty/non-JSON responses.

## Page data
- `getPageData()` → combined public payload for landing usage.

## Blog
- `getBlogPosts(filters?: BlogFilters)` → paginated transform.
- `getBlogPost(slug)`
- `getFeaturedBlogPosts()`
- `getBlogCategories()`
- `getBlogPostsByCategory(categorySlug, { page?, per_page? })`
- `getBlogPostsByTag(tag, { page?, per_page? })`
- `searchBlogPosts(query, { page?, per_page? })`
- `getRelatedBlogPosts(slug)`
47 changes: 47 additions & 0 deletions skills/appgram-react-native-sdk/references/components.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Components cheat sheet

Use inside `AppgramProvider`. All components are stylable via theme exports or props where noted.

## Feedback / Wishes
- `WishList`: full list + filters; props `title?`, `description?`, `filters?`, `showSubmitButton?`, `submitButtonText?`, callbacks `onWishPress`, `onWishSubmitted`, `onVote`, `onCommentPress`, `refreshInterval?`.
- `WishCard`: single wish card; props `wish`, `onPress`, `onVote`, `onCommentPress`.
- `VoteButton`: standalone vote UI; props `wishId`, `initialVoteCount`, `initialHasVoted`, `onVoteChange`.
- `WishDetailModal`: modal detail w/ comments & votes; props `wishId`, `visible`, `onClose`, `onVote`, `onComment`.
- `SubmitWishSheet`: sheet to create wish; props `visible`, `onClose`, `onSuccess`, `title?`, `description?`.

## Roadmap
- `RoadmapBoard`: Kanban-style columns; props `onItemPress?`, `refreshInterval?`.

## Releases / Changelog
- `Releases`: combined list + detail navigation; `onReleasePress?`.
- `ReleaseList`: list view; props `limit?`, `onReleasePress`.
- `ReleaseDetail`: single release; props `releaseSlug`, `onBack?`.

## Help Center
- `HelpCenter`: flows + articles overview; props `title?`, `onFlowPress`, `onArticlePress`.
- `HelpFlowCard`: summary card; props `flow`, `onPress`.
- `HelpFlowDetail`: flow detail; props `slug`, `onArticlePress`, `onBack?`.
- `HelpArticleCard`: article preview; props `article`, `onPress`.
- `HelpArticleDetail`: article content; props `slug`, `flowId?`, `onBack?`.

## Support & Forms
- `SupportForm`: ticket form; props `title?`, `userEmail?`, `userName?`, `onSuccess`, `onError?`.
- `FormRenderer`: render dynamic form by `formId`; props `formId`, `onSuccess?`, `onError?`.

## Surveys
- `SurveyForm`: interactive survey; props `slug`, `onSuccess`, `onError?`.

## Blog
- `Blog`: full blog view; props `title?`, `onPostPress`.
- `BlogList`: list with pagination/filter; props `category?`, `onPostPress`.
- `BlogCard`: card; props `post`, `onPress`.
- `BlogPostDetail`: article content; props `slug`, `onBack?`.

## Status
- `StatusBoard`: status + incidents; props `slug`, `refreshInterval?`.

## Chat
- `ChatScreen`: chat UI; uses `ChatSource` type; expects messages from Appgram client or custom source.

## Base UI
- `Button`, `Card`, `Badge`, `Input`: Hazel-themed primitives; accept standard RN text/input props plus style overrides.
58 changes: 58 additions & 0 deletions skills/appgram-react-native-sdk/references/hooks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Hooks cheat sheet

Each hook is headless: returns data, `isLoading`, often `error`, `refetch`, plus setters. Most support `refreshInterval` (ms) and `skip` for lazy load where provided. Use with `AppgramProvider` mounted.

## Feedback / Wishes
- `useWishes(options?: { filters?: WishFilters; refreshInterval?: number; skip?: boolean })`
- Returns `{ wishes, total, page, totalPages, isLoading, error, setFilters(filters), setPage(page), refetch }`
- Includes fingerprint when voting enabled; `setFilters` resets page to 1.
- `useVote({ onVote?, onError? }?)`
- Returns `{ vote(wishId, currentCount), unvote(wishId, voteId, currentCount), checkVote(wishId), isVoting, error }`
- Requires `fingerprint` (default enabled); `checkVote` safe if missing.
- `useComments({ wishId, autoFetch?, refreshInterval? })`
- Returns `{ comments, isLoading, error, isSubmitting, addComment(body, name?, email?), refetch }`

## Roadmap
- `useRoadmap({ refreshInterval? })`
- Returns `{ roadmap, columns, totalItems, isLoading, error, refetch }`

## Releases / Changelog
- `useReleases({ limit?, page?, refreshInterval? })`
- Returns `{ releases, isLoading, error, page, totalPages, setPage, refetch }`
- `useRelease({ releaseSlug, refreshInterval? })`
- Returns `{ release, features, isLoading, error, refetch }`

## Help Center
- `useHelpCenter()` → `{ collection, flows, isLoading, error }`
- `useHelpFlow(slug)` → `{ flow, isLoading, error }`
- `useHelpArticle(articleSlug, flowId?)` → `{ article, isLoading, error }`

## Support & Forms
- `useSupport({ onSuccess?, onError? }?)`
- Returns submission + auth helpers: `{ submitTicket(data), isSubmitting, error, successMessage, clearMessages, requestMagicLink(email), isSendingMagicLink, verifyToken(token), isVerifying, storedTickets, loadStoredTickets, clearStoredTickets }`
- Stores last 50 tickets in AsyncStorage (fallback to in-memory).
- `useForm(formId, { refreshInterval?, skip? }?)`
- `{ form, isLoading, error, refetch }`
- `useFormSubmit({ onSuccess?, onError? }?)`
- `{ submitForm(projectId, formId, payload), isSubmitting, error }`

## Surveys
- `useSurvey(slug, { refreshInterval?, skip? }?)`
- `{ survey, nodes, isLoading, error, refetch }`
- `useSurveySubmit({ onSuccess?, onError? }?)`
- `{ submitResponse(surveyId, payload), isSubmitting, error }`

## Blog
- `useBlogPosts({ category?, per_page?, page?, search?, refreshInterval? }?)`
- `{ posts, page, totalPages, setPage, setFilters, isLoading, error, refetch }`
- `useBlogPost({ slug })` → `{ post, relatedPosts, isLoading, error }`
- `useBlogCategories()` → `{ categories, isLoading, error }`
- `useFeaturedPosts()` → `{ posts, isLoading, error }`

## Status
- `useStatus({ slug, refreshInterval? })`
- `{ data, isLoading, error, refetch }`

## Shared utilities
- `useAppgramContext()` → `{ client, config, fingerprint, theme }`
- `useAppgramTheme()` → `{ colors, spacing, radius, typography, isDark, mode }`
36 changes: 36 additions & 0 deletions skills/appgram-react-native-sdk/references/platform-setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Platform setup & debugging

## Install & link
1) `npm install @appgram/react-native`
2) `npm install @react-native-async-storage/async-storage lucide-react-native react-native-svg react-native-markdown-display react-native-render-html`
3) iOS: `npx pod-install` (or `cd ios && pod install`).
4) Android: open Android Studio/Gradle sync or run `cd android && ./gradlew :app:assembleDebug` once to verify linking.

## Minimum versions
- React Native ≥0.70, React 18.
- react-native-svg ≥13, lucide-react-native ≥0.300.

## Common fixes
- Metro cache: `npm start -- --reset-cache`
- Watchman: `watchman watch-del-all` (if installed)
- Android clean build: `cd android && ./gradlew clean && ./gradlew :app:assembleDebug`
- iOS clean pods: `cd ios && rm -rf Pods Podfile.lock && pod install`
- Hermes mismatch: ensure RN version default Hermes enabled; if disabling Hermes, rebuild pods.
- Missing SVG icons: reinstall `react-native-svg` and `lucide-react-native`, then rebuild pods / Gradle.

## iOS notes
- If using Xcode, ensure the pods integrate with `use_frameworks!` defaults; no extra manual steps needed.
- For simulator fingerprinting issues, reset simulator content or clear AsyncStorage: `xcrun simctl erase all` (destructive) or uninstall the app.

## Android notes
- Ensure `mavenCentral()` is present in `android/build.gradle`.
- If release build crashes on SVG, check ProGuard/R8 rules; typically not needed, but you can keep `-keep class com.horcrux.svg.** { *; }` as a safeguard.
- AsyncStorage failing on Android emulator: wipe data via AVD Manager or reinstall app.

## Web (Expo / RNW)
- Components assume native; hooks can be used in Expo if dependencies are available; check markdown/html render libs compatibility on web.

## Validation checklist before shipping
- Run `npm run lint` and `npm run typecheck`.
- Build once: `npm run build` to ensure bob output.
- For app integrators: verify one happy-path flow per feature (wishlist vote, support submit, survey submit, blog post view, status load) on both platforms.
Loading