@appgram/react 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,420 @@
1
+ /**
2
+ * Wish (Feature Request) Types
3
+ */
4
+ type WishStatus = 'pending' | 'under_review' | 'planned' | 'in_progress' | 'completed' | 'declined';
5
+ type WishPriority = 'low' | 'medium' | 'high' | 'critical';
6
+ interface Category {
7
+ id: string;
8
+ name: string;
9
+ slug: string;
10
+ color: string;
11
+ icon?: string | null;
12
+ description?: string | null;
13
+ wish_count?: number;
14
+ }
15
+ interface WishAuthor {
16
+ name: string;
17
+ email?: string | null;
18
+ avatar_url?: string | null;
19
+ }
20
+ interface Wish {
21
+ id: string;
22
+ project_id: string;
23
+ category_id?: string | null;
24
+ title: string;
25
+ description: string;
26
+ status: WishStatus;
27
+ priority?: WishPriority | null;
28
+ author_type: 'user' | 'anonymous' | 'team_member';
29
+ author_email?: string | null;
30
+ author_name?: string | null;
31
+ vote_count: number;
32
+ comment_count: number;
33
+ slug: string;
34
+ is_pinned?: boolean;
35
+ created_at: string;
36
+ updated_at: string;
37
+ completed_at?: string | null;
38
+ category?: Category | null;
39
+ author?: WishAuthor;
40
+ has_voted?: boolean;
41
+ }
42
+ interface WishFilters {
43
+ status?: WishStatus | WishStatus[];
44
+ category_id?: string;
45
+ priority?: WishPriority | WishPriority[];
46
+ search?: string;
47
+ sort_by?: 'votes' | 'created_at' | 'updated_at';
48
+ sort_order?: 'asc' | 'desc';
49
+ page?: number;
50
+ per_page?: number;
51
+ fingerprint?: string;
52
+ }
53
+ interface WishesResponse {
54
+ data: Wish[];
55
+ total: number;
56
+ page: number;
57
+ per_page: number;
58
+ total_pages: number;
59
+ }
60
+
61
+ /**
62
+ * Comment Types
63
+ */
64
+ interface CommentAuthor {
65
+ name: string;
66
+ avatar_url?: string | null;
67
+ }
68
+ interface Comment {
69
+ id: string;
70
+ wish_id: string;
71
+ parent_id?: string | null;
72
+ author_type: 'user' | 'team_member' | 'anonymous';
73
+ author_user_id?: string | null;
74
+ author_name: string;
75
+ author_avatar_url?: string | null;
76
+ content: string;
77
+ is_official: boolean;
78
+ is_deleted: boolean;
79
+ reply_count: number;
80
+ created_at: string;
81
+ updated_at: string;
82
+ replies?: Comment[];
83
+ }
84
+ interface CommentCreateInput {
85
+ wish_id: string;
86
+ content: string;
87
+ author_name?: string;
88
+ author_email?: string;
89
+ parent_id?: string;
90
+ }
91
+ interface CommentsResponse {
92
+ data: Comment[];
93
+ total: number;
94
+ page: number;
95
+ per_page: number;
96
+ total_pages: number;
97
+ }
98
+
99
+ /**
100
+ * Roadmap Types
101
+ */
102
+
103
+ type RoadmapVisibility = 'public' | 'private' | 'voters_only';
104
+ interface Roadmap {
105
+ id: string;
106
+ project_id: string;
107
+ name: string;
108
+ description?: string | null;
109
+ visibility: RoadmapVisibility;
110
+ show_vote_counts: boolean;
111
+ show_comments: boolean;
112
+ is_default: boolean;
113
+ created_at: string;
114
+ updated_at: string;
115
+ columns?: RoadmapColumn[];
116
+ }
117
+ interface RoadmapColumn {
118
+ id: string;
119
+ roadmap_id: string;
120
+ name: string;
121
+ color: string;
122
+ sort_order: number;
123
+ wip_limit?: number | null;
124
+ created_at: string;
125
+ updated_at: string;
126
+ items?: RoadmapItem[];
127
+ }
128
+ interface RoadmapItem {
129
+ id: string;
130
+ roadmap_id: string;
131
+ column_id: string;
132
+ wish_id?: string | null;
133
+ title: string;
134
+ description?: string | null;
135
+ sort_order: number;
136
+ color?: string | null;
137
+ target_date?: string | null;
138
+ created_at: string;
139
+ updated_at: string;
140
+ wish?: Wish | null;
141
+ }
142
+ interface RoadmapData {
143
+ roadmap: Roadmap | null;
144
+ columns: RoadmapColumn[];
145
+ total_items: number;
146
+ customization?: {
147
+ use_custom: boolean;
148
+ customization_data: any;
149
+ } | null;
150
+ }
151
+
152
+ /**
153
+ * Release / Changelog Types
154
+ */
155
+ type ReleaseItemType = 'feature' | 'improvement' | 'bugfix' | 'other';
156
+ interface ReleaseItem {
157
+ id: string;
158
+ release_id: string;
159
+ title: string;
160
+ description?: string | null;
161
+ type: ReleaseItemType;
162
+ image_url?: string | null;
163
+ sort_order: number;
164
+ }
165
+ interface ReleaseFeature {
166
+ id: string;
167
+ release_id: string;
168
+ title: string;
169
+ description: string;
170
+ image_url?: string | null;
171
+ sort_order: number;
172
+ }
173
+ interface Release {
174
+ id: string;
175
+ project_id: string;
176
+ title: string;
177
+ content: string;
178
+ excerpt?: string | null;
179
+ cover_image_url?: string | null;
180
+ slug: string;
181
+ is_published: boolean;
182
+ published_at?: string | null;
183
+ version?: string | null;
184
+ labels: string[];
185
+ wish_ids: string[];
186
+ author_user_id: string;
187
+ created_at: string;
188
+ updated_at: string;
189
+ features?: ReleaseFeature[];
190
+ items?: ReleaseItem[];
191
+ }
192
+ interface ReleasesResponse {
193
+ data: Release[];
194
+ total: number;
195
+ page: number;
196
+ per_page: number;
197
+ total_pages: number;
198
+ }
199
+
200
+ /**
201
+ * Help Center Types
202
+ */
203
+ type ArticleType = 'guide' | 'faq' | 'tutorial';
204
+ type FlowDisplayType = 'list' | 'accordion' | 'decision_tree' | 'wizard';
205
+ interface HelpArticle {
206
+ id: string;
207
+ flow_id: string;
208
+ title: string;
209
+ slug: string;
210
+ content: string;
211
+ excerpt?: string | null;
212
+ article_type: ArticleType;
213
+ is_published: boolean;
214
+ sort_order: number;
215
+ published_at?: string | null;
216
+ created_at: string;
217
+ updated_at: string;
218
+ }
219
+ interface HelpFlow {
220
+ id: string;
221
+ collection_id: string;
222
+ name: string;
223
+ slug: string;
224
+ description?: string | null;
225
+ icon?: string | null;
226
+ color?: string | null;
227
+ display_type: FlowDisplayType;
228
+ sort_order: number;
229
+ created_at: string;
230
+ updated_at: string;
231
+ articles?: HelpArticle[];
232
+ }
233
+ interface HelpCollection {
234
+ id: string;
235
+ project_id: string;
236
+ name: string;
237
+ version: string;
238
+ description?: string | null;
239
+ is_live: boolean;
240
+ created_at: string;
241
+ updated_at: string;
242
+ flows?: HelpFlow[];
243
+ }
244
+ interface HelpCenterData {
245
+ collection: HelpCollection | null;
246
+ flows: HelpFlow[];
247
+ }
248
+ interface HelpArticlesResponse {
249
+ data: HelpArticle[];
250
+ total: number;
251
+ page: number;
252
+ per_page: number;
253
+ total_pages: number;
254
+ }
255
+
256
+ /**
257
+ * Support Types
258
+ */
259
+ type SupportRequestStatus = 'new' | 'open' | 'in_progress' | 'resolved' | 'closed';
260
+ type SupportRequestPriority = 'low' | 'medium' | 'high' | 'critical';
261
+ type SupportRequestCategory = 'bug_report' | 'feature_request' | 'general_inquiry' | 'billing' | 'account';
262
+ interface SupportAttachment {
263
+ url: string;
264
+ name: string;
265
+ size: number;
266
+ mime_type?: string;
267
+ }
268
+ interface SupportMessage {
269
+ id: string;
270
+ support_request_id: string;
271
+ author_type: 'user' | 'team_member';
272
+ author_user_id?: string | null;
273
+ author_email?: string | null;
274
+ author_name?: string | null;
275
+ content: string;
276
+ is_internal: boolean;
277
+ attachments?: SupportAttachment[];
278
+ created_at: string;
279
+ }
280
+ interface SupportRequest {
281
+ id: string;
282
+ project_id: string;
283
+ subject: string;
284
+ description: string;
285
+ status: SupportRequestStatus;
286
+ priority?: SupportRequestPriority | null;
287
+ category?: SupportRequestCategory | null;
288
+ user_email: string;
289
+ user_name?: string | null;
290
+ assignee_id?: string | null;
291
+ message_count: number;
292
+ created_at: string;
293
+ updated_at: string;
294
+ resolved_at?: string | null;
295
+ messages?: SupportMessage[];
296
+ attachments?: SupportAttachment[];
297
+ }
298
+ interface SupportRequestInput {
299
+ subject: string;
300
+ description: string;
301
+ user_email: string;
302
+ user_name?: string;
303
+ category?: SupportRequestCategory;
304
+ attachments?: File[];
305
+ }
306
+ interface SupportRequestsResponse {
307
+ data: SupportRequest[];
308
+ total: number;
309
+ page: number;
310
+ per_page: number;
311
+ total_pages: number;
312
+ }
313
+
314
+ /**
315
+ * useVote Hook
316
+ *
317
+ * Manages voting state and actions for a wish.
318
+ * Provides optimistic updates for instant UI feedback.
319
+ *
320
+ * @example
321
+ * ```tsx
322
+ * import { useVote } from '@appgram/react'
323
+ *
324
+ * function VoteButton({ wishId, initialCount, initialHasVoted }) {
325
+ * const { hasVoted, voteCount, toggle, isLoading } = useVote({
326
+ * wishId,
327
+ * initialVoteCount: initialCount,
328
+ * initialHasVoted,
329
+ * onVoteChange: (voted, count) => {
330
+ * analytics.track('vote', { wishId, voted })
331
+ * }
332
+ * })
333
+ *
334
+ * return (
335
+ * <button
336
+ * onClick={toggle}
337
+ * disabled={isLoading}
338
+ * className={hasVoted ? 'voted' : ''}
339
+ * >
340
+ * {hasVoted ? '✓' : '▲'} {voteCount}
341
+ * </button>
342
+ * )
343
+ * }
344
+ * ```
345
+ *
346
+ * @example
347
+ * ```tsx
348
+ * // Lazy vote check to avoid rate limiting
349
+ * const { hasVoted, voteCount, toggle } = useVote({
350
+ * wishId: wish.id,
351
+ * initialVoteCount: wish.vote_count,
352
+ * skipAutoCheck: true, // Check on first click instead
353
+ * })
354
+ * ```
355
+ */
356
+ interface UseVoteOptions {
357
+ /**
358
+ * The wish ID to vote on
359
+ */
360
+ wishId: string;
361
+ /**
362
+ * Initial vote count (optional, useful when you already have the wish data)
363
+ */
364
+ initialVoteCount?: number;
365
+ /**
366
+ * Initial hasVoted state (optional)
367
+ */
368
+ initialHasVoted?: boolean;
369
+ /**
370
+ * Voter email (optional, for identified voting)
371
+ */
372
+ voterEmail?: string;
373
+ /**
374
+ * Callback when vote state changes
375
+ */
376
+ onVoteChange?: (hasVoted: boolean, voteCount: number) => void;
377
+ /**
378
+ * Skip automatic vote check on mount to avoid rate limiting
379
+ * When true, vote status will be checked lazily on first interaction
380
+ * @default true
381
+ */
382
+ skipAutoCheck?: boolean;
383
+ }
384
+ interface UseVoteResult {
385
+ /**
386
+ * Whether the current user has voted
387
+ */
388
+ hasVoted: boolean;
389
+ /**
390
+ * Current vote count
391
+ */
392
+ voteCount: number;
393
+ /**
394
+ * Loading state for vote operations
395
+ */
396
+ isLoading: boolean;
397
+ /**
398
+ * Loading state for initial vote check
399
+ */
400
+ isChecking: boolean;
401
+ /**
402
+ * Error message if any
403
+ */
404
+ error: string | null;
405
+ /**
406
+ * Toggle vote (vote if not voted, unvote if voted)
407
+ */
408
+ toggle: () => Promise<void>;
409
+ /**
410
+ * Cast a vote
411
+ */
412
+ vote: () => Promise<void>;
413
+ /**
414
+ * Remove a vote
415
+ */
416
+ unvote: () => Promise<void>;
417
+ }
418
+ declare function useVote(options: UseVoteOptions): UseVoteResult;
419
+
420
+ export { type ArticleType as A, type WishPriority as B, type CommentsResponse as C, type WishStatus as D, useVote as E, type FlowDisplayType as F, type HelpCollection as H, type RoadmapData as R, type SupportRequestInput as S, type UseVoteOptions as U, type WishFilters as W, type WishesResponse as a, type Wish as b, type Comment as c, type Release as d, type ReleaseFeature as e, type HelpFlow as f, type HelpArticle as g, type SupportRequest as h, type Category as i, type CommentAuthor as j, type CommentCreateInput as k, type HelpArticlesResponse as l, type HelpCenterData as m, type ReleasesResponse as n, type Roadmap as o, type RoadmapColumn as p, type RoadmapItem as q, type RoadmapVisibility as r, type SupportAttachment as s, type SupportMessage as t, type SupportRequestCategory as u, type SupportRequestPriority as v, type SupportRequestStatus as w, type SupportRequestsResponse as x, type UseVoteResult as y, type WishAuthor as z };
package/package.json ADDED
@@ -0,0 +1,82 @@
1
+ {
2
+ "name": "@appgram/react",
3
+ "version": "0.1.0",
4
+ "description": "React library for integrating Appgram portal features with pre-built UI components and headless hooks",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ },
14
+ "./hooks": {
15
+ "types": "./dist/hooks/index.d.ts",
16
+ "import": "./dist/hooks/index.mjs",
17
+ "require": "./dist/hooks/index.js"
18
+ },
19
+ "./components": {
20
+ "types": "./dist/components/index.d.ts",
21
+ "import": "./dist/components/index.mjs",
22
+ "require": "./dist/components/index.js"
23
+ },
24
+ "./tailwind-preset": "./tailwind-preset.js"
25
+ },
26
+ "files": [
27
+ "dist",
28
+ "tailwind-preset.js"
29
+ ],
30
+ "sideEffects": false,
31
+ "scripts": {
32
+ "build": "tsup",
33
+ "dev": "tsup --watch",
34
+ "typecheck": "tsc --noEmit",
35
+ "lint": "eslint src/",
36
+ "clean": "rm -rf dist",
37
+ "demo": "npm run build && cd demo && npm install && npm run dev",
38
+ "demo:install": "cd demo && npm install",
39
+ "demo:dev": "cd demo && npm run dev",
40
+ "docs:json": "npx typedoc --json docs.json --entryPoints src/index.ts",
41
+ "docs:transform": "node transform-docs.js",
42
+ "docs:build": "npm run docs:json && npm run docs:transform"
43
+ },
44
+ "peerDependencies": {
45
+ "react": ">=18.0.0",
46
+ "react-dom": ">=18.0.0"
47
+ },
48
+ "dependencies": {
49
+ "clsx": "^2.1.0",
50
+ "dompurify": "^3.3.1",
51
+ "framer-motion": "^11.0.0",
52
+ "lucide-react": "^0.400.0",
53
+ "react-markdown": "^9.0.0",
54
+ "remark-gfm": "^4.0.0",
55
+ "tailwind-merge": "^2.2.0"
56
+ },
57
+ "devDependencies": {
58
+ "@types/dompurify": "^3.0.5",
59
+ "@types/react": "^18.2.0",
60
+ "@types/react-dom": "^18.2.0",
61
+ "react": "^18.2.0",
62
+ "react-dom": "^18.2.0",
63
+ "tsup": "^8.0.0",
64
+ "typedoc": "^0.26.11",
65
+ "typescript": "^5.3.0"
66
+ },
67
+ "repository": {
68
+ "type": "git",
69
+ "url": "https://github.com/appgram/react"
70
+ },
71
+ "keywords": [
72
+ "react",
73
+ "appgram",
74
+ "feedback",
75
+ "roadmap",
76
+ "feature-requests",
77
+ "changelog",
78
+ "support"
79
+ ],
80
+ "author": "Appgram",
81
+ "license": "MIT"
82
+ }
@@ -0,0 +1,48 @@
1
+ /** @type {import('tailwindcss').Config} */
2
+ module.exports = {
3
+ theme: {
4
+ extend: {
5
+ colors: {
6
+ appgram: {
7
+ primary: 'var(--appgram-primary, #6366f1)',
8
+ secondary: 'var(--appgram-secondary, #8b5cf6)',
9
+ accent: 'var(--appgram-accent, #06b6d4)',
10
+ background: 'var(--appgram-background, #ffffff)',
11
+ foreground: 'var(--appgram-foreground, #09090b)',
12
+ muted: 'var(--appgram-muted, #f4f4f5)',
13
+ 'muted-foreground': 'var(--appgram-muted-foreground, #71717a)',
14
+ card: 'var(--appgram-card, #ffffff)',
15
+ 'card-foreground': 'var(--appgram-card-foreground, #09090b)',
16
+ border: 'var(--appgram-border, #e4e4e7)',
17
+ },
18
+ },
19
+ borderRadius: {
20
+ appgram: 'var(--appgram-radius, 0.5rem)',
21
+ },
22
+ fontFamily: {
23
+ appgram: 'var(--appgram-font-family, inherit)',
24
+ },
25
+ animation: {
26
+ 'appgram-fade-in': 'appgram-fade-in 0.3s ease-out',
27
+ 'appgram-slide-up': 'appgram-slide-up 0.3s ease-out',
28
+ 'appgram-vote-pop': 'appgram-vote-pop 0.4s ease-out',
29
+ },
30
+ keyframes: {
31
+ 'appgram-fade-in': {
32
+ '0%': { opacity: '0' },
33
+ '100%': { opacity: '1' },
34
+ },
35
+ 'appgram-slide-up': {
36
+ '0%': { opacity: '0', transform: 'translateY(10px)' },
37
+ '100%': { opacity: '1', transform: 'translateY(0)' },
38
+ },
39
+ 'appgram-vote-pop': {
40
+ '0%': { transform: 'scale(1)' },
41
+ '50%': { transform: 'scale(1.2)' },
42
+ '100%': { transform: 'scale(1)' },
43
+ },
44
+ },
45
+ },
46
+ },
47
+ plugins: [],
48
+ }