Skip to content

Commit 258a86b

Browse files
committed
feat: add story persistance and queuing stories
1 parent 1aeeea0 commit 258a86b

File tree

18 files changed

+1764
-445
lines changed

18 files changed

+1764
-445
lines changed

client/src/Home.tsx

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ export const Home = () => {
1414
const [storedSession, setStoredSession] = useState<string | null>(null);
1515
const [showRejoinPrompt, setShowRejoinPrompt] = useState(false);
1616
const [notification, setNotification] = useState<string | null>(null);
17+
const [showCustomSessionModal, setShowCustomSessionModal] = useState(false);
18+
const [customSessionId, setCustomSessionId] = useState('');
1719
const [darkMode, setDarkMode] = useState<boolean>(() => {
1820
const stored = localStorage.getItem(STORAGE_KEY_DARK_MODE);
1921
return stored === 'true';
@@ -50,17 +52,33 @@ export const Home = () => {
5052
setStoredSession(null);
5153
};
5254

53-
const createSession = async () => {
55+
const createSession = () => {
5456
if (!userName.trim()) {
5557
setNotification('Please enter your name');
5658
return;
5759
}
60+
setShowCustomSessionModal(true);
61+
};
5862

63+
const confirmCreateSession = async () => {
5964
setLoading(true);
65+
setShowCustomSessionModal(false);
66+
6067
try {
68+
const body = customSessionId.trim() ? { sessionId: customSessionId.trim() } : undefined;
6169
const response = await fetch('/api/session', {
6270
method: 'POST',
71+
headers: body ? { 'Content-Type': 'application/json' } : {},
72+
body: body ? JSON.stringify(body) : undefined,
6373
});
74+
75+
if (!response.ok) {
76+
const error = await response.json();
77+
setNotification(error.error || 'Failed to create session');
78+
setLoading(false);
79+
return;
80+
}
81+
6482
const data = await response.json();
6583

6684
localStorage.setItem(STORAGE_KEY_USERNAME, userName);
@@ -72,6 +90,7 @@ export const Home = () => {
7290
setNotification('Failed to create session');
7391
} finally {
7492
setLoading(false);
93+
setCustomSessionId('');
7594
}
7695
};
7796

@@ -142,6 +161,42 @@ export const Home = () => {
142161
{notification && (
143162
<Notification message={notification} onClose={() => setNotification(null)} />
144163
)}
164+
{showCustomSessionModal && (
165+
<div style={styles.modalOverlay} onClick={() => setShowCustomSessionModal(false)}>
166+
<div style={styles.modalContent} onClick={(e) => e.stopPropagation()}>
167+
<h2 style={styles.modalTitle}>Create New Session</h2>
168+
<p style={styles.modalDescription}>
169+
Enter a custom session name (optional) or leave blank to auto-generate
170+
</p>
171+
<input
172+
type="text"
173+
value={customSessionId}
174+
onChange={(e) => setCustomSessionId(e.target.value)}
175+
placeholder="Custom session name (optional)"
176+
style={styles.modalInput}
177+
autoFocus
178+
/>
179+
<div style={styles.modalButtons}>
180+
<button
181+
onClick={() => {
182+
setShowCustomSessionModal(false);
183+
setCustomSessionId('');
184+
}}
185+
style={styles.cancelButton}
186+
>
187+
Cancel
188+
</button>
189+
<button
190+
onClick={confirmCreateSession}
191+
style={styles.confirmButton}
192+
disabled={loading}
193+
>
194+
{loading ? 'Creating...' : 'Create Session'}
195+
</button>
196+
</div>
197+
</div>
198+
</div>
199+
)}
145200
</div>
146201
);
147202
};
@@ -168,4 +223,71 @@ const getStyles = (colors: any): { [key: string]: React.CSSProperties } => ({
168223
borderRadius: '4px',
169224
cursor: 'pointer',
170225
},
226+
modalOverlay: {
227+
position: 'fixed',
228+
top: 0,
229+
left: 0,
230+
right: 0,
231+
bottom: 0,
232+
backgroundColor: 'rgba(0, 0, 0, 0.5)',
233+
display: 'flex',
234+
alignItems: 'center',
235+
justifyContent: 'center',
236+
zIndex: 1000,
237+
},
238+
modalContent: {
239+
backgroundColor: colors.surface,
240+
borderRadius: '8px',
241+
padding: '24px',
242+
maxWidth: '500px',
243+
width: '100%',
244+
margin: '20px',
245+
},
246+
modalTitle: {
247+
fontSize: '24px',
248+
fontWeight: 'bold',
249+
marginBottom: '12px',
250+
color: colors.text,
251+
},
252+
modalDescription: {
253+
fontSize: '14px',
254+
color: colors.textSecondary,
255+
marginBottom: '20px',
256+
},
257+
modalInput: {
258+
width: '100%',
259+
padding: '12px',
260+
fontSize: '16px',
261+
border: `2px solid ${colors.border}`,
262+
borderRadius: '4px',
263+
marginBottom: '20px',
264+
backgroundColor: colors.surface,
265+
color: colors.text,
266+
boxSizing: 'border-box',
267+
},
268+
modalButtons: {
269+
display: 'flex',
270+
gap: '12px',
271+
justifyContent: 'flex-end',
272+
},
273+
cancelButton: {
274+
padding: '10px 20px',
275+
fontSize: '14px',
276+
fontWeight: '600',
277+
backgroundColor: colors.surface,
278+
color: colors.text,
279+
border: `2px solid ${colors.border}`,
280+
borderRadius: '4px',
281+
cursor: 'pointer',
282+
},
283+
confirmButton: {
284+
padding: '10px 20px',
285+
fontSize: '14px',
286+
fontWeight: '600',
287+
backgroundColor: colors.primary,
288+
color: 'white',
289+
border: 'none',
290+
borderRadius: '4px',
291+
cursor: 'pointer',
292+
},
171293
});

0 commit comments

Comments
 (0)