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
22 changes: 20 additions & 2 deletions UI/Plot.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,29 @@
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,400;12..96,500;12..96,600;12..96,700;12..96,800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
html, body { margin: 0; padding: 0; background: #1E1B4B; min-height: 100vh; }
body { font-family: 'Bricolage Grotesque', system-ui, sans-serif; -webkit-font-smoothing: antialiased; }
/* Use dvh on supported browsers (iOS 15.4+, Chrome 108+) so the layout
follows the visible viewport instead of the static one — fixes the
"bottom nav hidden under Safari address bar" problem. */
html, body {
margin: 0; padding: 0;
background: #1E1B4B;
min-height: 100vh;
min-height: 100dvh;
overscroll-behavior-y: none;
}
body {
font-family: 'Bricolage Grotesque', system-ui, sans-serif;
-webkit-font-smoothing: antialiased;
/* Pad for the iOS notch + home-indicator on devices that report safe areas. */
padding-top: env(safe-area-inset-top, 0px);
padding-bottom: env(safe-area-inset-bottom, 0px);
}
* { box-sizing: border-box; }
::-webkit-scrollbar { width: 0; background: transparent; }
button { font-family: inherit; }
/* The fullscreen root container uses 100dvh too so the iOS dynamic
viewport stays consistent — overrides any inline 100vh from app.jsx. */
#root { min-height: 100vh; min-height: 100dvh; }
</style>

<script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
Expand Down
17 changes: 16 additions & 1 deletion UI/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,12 @@ window.PLOT_API = (function () {

// ── /groups (multi-user shareable-link sessions) ─────────────────

function createGroup(name, displayName) {
function createGroup(name, displayName, eventDate) {
return call('POST', '/groups', {
name,
creator_user_id: getUserId(),
creator_display_name: displayName || null,
event_date: eventDate || null,
});
}

Expand All @@ -161,6 +162,18 @@ window.PLOT_API = (function () {
});
}

function leaveGroup(groupId) {
return call('POST', `/groups/${encodeURIComponent(groupId)}/leave`, {
user_id: getUserId(),
});
}

function deleteGroup(groupId) {
return call('POST', `/groups/${encodeURIComponent(groupId)}/delete`, {
user_id: getUserId(),
});
}

function setGroupPrefs(groupId, prefs) {
return call('POST', `/groups/${encodeURIComponent(groupId)}/prefs`, {
user_id: getUserId(),
Expand Down Expand Up @@ -447,6 +460,8 @@ window.PLOT_API = (function () {
createGroup,
peekGroupByToken,
joinGroupAPI,
leaveGroup,
deleteGroup,
setGroupPrefs,
getGroupState,
groupRecommend,
Expand Down
25 changes: 23 additions & 2 deletions UI/app.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -284,11 +284,23 @@ function PlotApp() {

// Profile / Home → "leave group" returns to solo mode. We don't delete
// the group server-side (other members keep planning); just clear our
// local context AND any stale per-group state.
function handleLeaveGroup() {
// local context AND any stale per-group state. Best-effort call to the
// backend to delete our group_members row — if the network fails we still
// clear locally so the user isn't stuck staring at a group they wanted
// to leave. They'll re-appear in the list on next refresh if the API
// call didn't actually land, which is the right safety behavior.
async function handleLeaveGroup() {
const gid = currentGroup && currentGroup.id;
_clearGroupSessionState();
setCurrentGroup(null);
setScreen('home');
if (gid) {
try {
await window.PLOT_API.leaveGroup(gid);
} catch (e) {
console.warn('leaveGroup API failed (non-fatal):', e);
}
}
}

// "We went" tap on Group Decision: log the strongest feedback signal
Expand Down Expand Up @@ -411,6 +423,15 @@ function PlotApp() {
}}
/>
)}
{/* Global toast notification host. Mounted once at root; any code
can fire toasts via window.plotToast(msg, kind). */}
<ToastHost />
{/* Global confetti host. Mounted at root so window.plotConfetti()
works even when the firing screen navigates away mid-animation. */}
<ConfettiHost />
{/* Global coin-shower host — fires from BudgetChip taps via
window.plotCoinShower(count). Same pattern as ConfettiHost. */}
<CoinShowerHost />
</div>
);

Expand Down
Loading
Loading