create-githat-app 1.8.3 → 1.8.6

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.
Files changed (46) hide show
  1. package/dist/cli.js +2 -2
  2. package/package.json +1 -1
  3. package/templates/agent/app/(auth)/sign-in/magic/page.tsx.hbs +11 -0
  4. package/templates/agent/app/account/activity/page.tsx.hbs +176 -0
  5. package/templates/agent/app/account/security/page.tsx.hbs +46 -0
  6. package/templates/agent/app/account/sessions/page.tsx.hbs +180 -0
  7. package/templates/base/README.md.hbs +102 -0
  8. package/templates/classroom/app/(auth)/sign-in/magic/page.tsx.hbs +11 -0
  9. package/templates/classroom/app/account/activity/page.tsx.hbs +176 -0
  10. package/templates/classroom/app/account/security/page.tsx.hbs +46 -0
  11. package/templates/classroom/app/account/sessions/page.tsx.hbs +180 -0
  12. package/templates/content/app/(auth)/sign-in/magic/page.tsx.hbs +11 -0
  13. package/templates/content/app/account/activity/page.tsx.hbs +176 -0
  14. package/templates/content/app/account/security/page.tsx.hbs +46 -0
  15. package/templates/content/app/account/sessions/page.tsx.hbs +180 -0
  16. package/templates/dashboard/app/(auth)/sign-in/magic/page.tsx.hbs +11 -0
  17. package/templates/dashboard/app/account/activity/page.tsx.hbs +176 -0
  18. package/templates/dashboard/app/account/security/page.tsx.hbs +46 -0
  19. package/templates/dashboard/app/account/sessions/page.tsx.hbs +180 -0
  20. package/templates/marketplace/app/(auth)/sign-in/magic/page.tsx.hbs +11 -0
  21. package/templates/marketplace/app/account/activity/page.tsx.hbs +176 -0
  22. package/templates/marketplace/app/account/security/page.tsx.hbs +46 -0
  23. package/templates/marketplace/app/account/sessions/page.tsx.hbs +180 -0
  24. package/templates/marketplace/app/admin/page.tsx.hbs +19 -19
  25. package/templates/marketplace/app/cart/page.tsx.hbs +23 -21
  26. package/templates/marketplace/app/layout.tsx.hbs +7 -7
  27. package/templates/marketplace/app/page.tsx.hbs +82 -31
  28. package/templates/marketplace/app/sell/page.tsx.hbs +17 -18
  29. package/templates/marketplace/src/data/products.ts.hbs +64 -0
  30. package/templates/marketplace/src/lib/categories.ts.hbs +17 -23
  31. package/templates/nextjs/app/(auth)/sign-in/magic/page.tsx.hbs +11 -0
  32. package/templates/nextjs/app/account/activity/page.tsx.hbs +176 -0
  33. package/templates/nextjs/app/account/security/page.tsx.hbs +46 -0
  34. package/templates/nextjs/app/account/sessions/page.tsx.hbs +180 -0
  35. package/templates/plain/app/(auth)/sign-in/magic/page.tsx.hbs +11 -0
  36. package/templates/plain/app/account/activity/page.tsx.hbs +176 -0
  37. package/templates/plain/app/account/security/page.tsx.hbs +46 -0
  38. package/templates/plain/app/account/sessions/page.tsx.hbs +180 -0
  39. package/templates/portfolio/app/(auth)/sign-in/magic/page.tsx.hbs +11 -0
  40. package/templates/portfolio/app/account/activity/page.tsx.hbs +176 -0
  41. package/templates/portfolio/app/account/security/page.tsx.hbs +46 -0
  42. package/templates/portfolio/app/account/sessions/page.tsx.hbs +180 -0
  43. package/templates/saas/app/(auth)/sign-in/magic/page.tsx.hbs +11 -0
  44. package/templates/saas/app/account/activity/page.tsx.hbs +176 -0
  45. package/templates/saas/app/account/security/page.tsx.hbs +46 -0
  46. package/templates/saas/app/account/sessions/page.tsx.hbs +180 -0
@@ -0,0 +1,180 @@
1
+ 'use client';
2
+
3
+ import { useEffect, useState } from 'react';
4
+ import { useSessions } from '@githat/nextjs';
5
+ import type { Session } from '@githat/nextjs';
6
+
7
+ /**
8
+ * /account/sessions — Active session management for {{businessName}}.
9
+ *
10
+ * Lists all active sessions with device/IP/country info.
11
+ * Users can revoke individual sessions or sign out everywhere else.
12
+ */
13
+ export default function SessionsPage() {
14
+ const { list, revoke, revokeAll } = useSessions();
15
+ const [sessions, setSessions] = useState<Session[]>([]);
16
+ const [loading, setLoading] = useState(true);
17
+ const [error, setError] = useState<string | null>(null);
18
+ const [revoking, setRevoking] = useState<string | null>(null);
19
+ const [revokingAll, setRevokingAll] = useState(false);
20
+
21
+ async function load() {
22
+ setLoading(true);
23
+ setError(null);
24
+ try {
25
+ const { sessions: data } = await list();
26
+ setSessions(data);
27
+ } catch (err: unknown) {
28
+ setError(err instanceof Error ? err.message : 'Failed to load sessions');
29
+ } finally {
30
+ setLoading(false);
31
+ }
32
+ }
33
+
34
+ useEffect(() => { load(); }, []);
35
+
36
+ async function handleRevoke(sessionId: string) {
37
+ setRevoking(sessionId);
38
+ try {
39
+ await revoke(sessionId);
40
+ setSessions((prev) => prev.filter((s) => s.id !== sessionId));
41
+ } catch (err: unknown) {
42
+ setError(err instanceof Error ? err.message : 'Failed to revoke session');
43
+ } finally {
44
+ setRevoking(null);
45
+ }
46
+ }
47
+
48
+ async function handleRevokeAll() {
49
+ if (!confirm('Sign out of all other devices?')) return;
50
+ setRevokingAll(true);
51
+ try {
52
+ await revokeAll();
53
+ setSessions((prev) => prev.filter((s) => s.current));
54
+ } catch (err: unknown) {
55
+ setError(err instanceof Error ? err.message : 'Failed to revoke sessions');
56
+ } finally {
57
+ setRevokingAll(false);
58
+ }
59
+ }
60
+
61
+ const otherCount = sessions.filter((s) => !s.current).length;
62
+
63
+ return (
64
+ <main
65
+ style=\{{
66
+ maxWidth: '720px',
67
+ margin: '0 auto',
68
+ padding: 'var(--space-8, 2rem) var(--space-4, 1rem)',
69
+ color: 'var(--fg, #111)',
70
+ }}
71
+ >
72
+ <header style=\{{ marginBottom: '1.5rem' }}>
73
+ <div style=\{{ display: 'flex', alignItems: 'center', gap: '0.5rem', marginBottom: '0.25rem' }}>
74
+ <a href="/account/security" style=\{{ color: 'var(--fg-muted, #666)', textDecoration: 'none', fontSize: '0.875rem' }}>
75
+ Security
76
+ </a>
77
+ <span style=\{{ color: 'var(--fg-muted, #666)' }}>›</span>
78
+ <span style=\{{ fontSize: '0.875rem' }}>Active sessions</span>
79
+ </div>
80
+ <h1 style=\{{ fontSize: '1.875rem', fontWeight: 700, margin: 0 }}>Active sessions</h1>
81
+ <p style=\{{ color: 'var(--fg-muted, #666)', marginTop: '0.25rem' }}>
82
+ Devices signed in to your {{businessName}} account.
83
+ </p>
84
+ </header>
85
+
86
+ {error && (
87
+ <div style=\{{ padding: '0.75rem 1rem', background: '#fef2f2', border: '1px solid #fecaca', borderRadius: '6px', color: '#dc2626', marginBottom: '1rem' }}>
88
+ {error}
89
+ </div>
90
+ )}
91
+
92
+ {otherCount > 0 && (
93
+ <div style=\{{ marginBottom: '1.5rem' }}>
94
+ <button
95
+ onClick={handleRevokeAll}
96
+ disabled={revokingAll}
97
+ style=\{{
98
+ padding: '0.5rem 1.25rem',
99
+ background: '#fef2f2',
100
+ color: '#dc2626',
101
+ border: '1px solid #fecaca',
102
+ borderRadius: '6px',
103
+ cursor: revokingAll ? 'not-allowed' : 'pointer',
104
+ fontWeight: 500,
105
+ }}
106
+ >
107
+ {revokingAll ? 'Signing out...' : `Sign out everywhere else (${otherCount})`}
108
+ </button>
109
+ </div>
110
+ )}
111
+
112
+ {loading ? (
113
+ <p style=\{{ color: 'var(--fg-muted, #666)' }}>Loading sessions...</p>
114
+ ) : sessions.length === 0 ? (
115
+ <p style=\{{ color: 'var(--fg-muted, #666)' }}>No active sessions found.</p>
116
+ ) : (
117
+ <div style=\{{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
118
+ {sessions.map((session) => (
119
+ <div
120
+ key={session.id}
121
+ style=\{{
122
+ padding: '1rem 1.25rem',
123
+ border: session.current ? '1px solid #6366f1' : '1px solid var(--border, #e5e7eb)',
124
+ borderRadius: '8px',
125
+ display: 'flex',
126
+ justifyContent: 'space-between',
127
+ alignItems: 'flex-start',
128
+ gap: '1rem',
129
+ }}
130
+ >
131
+ <div style=\{{ flex: 1, minWidth: 0 }}>
132
+ <div style=\{{ display: 'flex', alignItems: 'center', gap: '0.5rem', marginBottom: '0.25rem' }}>
133
+ <span style=\{{ fontWeight: 600, fontSize: '0.9rem', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
134
+ {session.userAgent || 'Unknown device'}
135
+ </span>
136
+ {session.current && (
137
+ <span style=\{{
138
+ padding: '0.1rem 0.5rem',
139
+ background: '#ede9fe',
140
+ color: '#6366f1',
141
+ borderRadius: '999px',
142
+ fontSize: '0.75rem',
143
+ fontWeight: 600,
144
+ whiteSpace: 'nowrap',
145
+ }}>
146
+ This device
147
+ </span>
148
+ )}
149
+ </div>
150
+ <div style=\{{ fontSize: '0.8rem', color: 'var(--fg-muted, #666)', display: 'flex', gap: '0.75rem', flexWrap: 'wrap' }}>
151
+ {session.ipAddress && <span>{session.ipAddress}</span>}
152
+ {session.country && <span>{session.country}</span>}
153
+ <span>Last active {new Date(session.lastActiveAt).toLocaleDateString()}</span>
154
+ </div>
155
+ </div>
156
+ {!session.current && (
157
+ <button
158
+ onClick={() => handleRevoke(session.id)}
159
+ disabled={revoking === session.id}
160
+ style=\{{
161
+ padding: '0.375rem 0.875rem',
162
+ background: 'transparent',
163
+ border: '1px solid var(--border, #e5e7eb)',
164
+ borderRadius: '6px',
165
+ cursor: revoking === session.id ? 'not-allowed' : 'pointer',
166
+ fontSize: '0.875rem',
167
+ whiteSpace: 'nowrap',
168
+ flexShrink: 0,
169
+ }}
170
+ >
171
+ {revoking === session.id ? 'Revoking...' : 'Revoke'}
172
+ </button>
173
+ )}
174
+ </div>
175
+ ))}
176
+ </div>
177
+ )}
178
+ </main>
179
+ );
180
+ }