Skip to content

Commit 13e0aac

Browse files
Easier past-experience logging + a header bug-report button
Two changes to lower friction on things that were awkward or buried. Log a past experience: - The "+ Session" form gains a "This already happened" checkbox. When ticked it reveals an end-time field, reframes the start field, and changes the action from "Start" to "Log it". On submit the session is created already ended (via end_experience, falling back to the start time if no end was given), so it reads as history — no "ongoing", no live-session controls — instead of the old route of starting a session, backdating it, and ending it by hand with a wrong end time. - New doses added to a session that's already over now default their time to the session's start rather than "now", so writing up a past trip doesn't mean fixing every dose timestamp. Live sessions and notes still default to now. Report a bug from anywhere: - A "🐛 Report a bug" button on the header bar opens a small modal with the same prefilled-GitHub-issue flow that previously lived only in a Settings card. The Settings card stays; this is just a faster way in. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 0b287a0 commit 13e0aac

1 file changed

Lines changed: 89 additions & 6 deletions

File tree

src/routes/+page.svelte

Lines changed: 89 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,10 @@
152152
let neIntention = $state("");
153153
let neSetting = $state("");
154154
let neStart = $state("");
155+
// "This already happened" — when set, the session is created already ended
156+
// (with `neEnd`) so it reads as history rather than an ongoing session.
157+
let nePast = $state(false);
158+
let neEnd = $state("");
155159
let showNewExp = $state(false);
156160
// plain note (kind: "note") — title, body, date; nothing else
157161
let nnTitle = $state("");
@@ -676,14 +680,23 @@
676680
usage = await usageBySubstance();
677681
}
678682
683+
/** What a fresh dose-time field should default to. For a session that already
684+
* ended (a past trip being written up), new doses belong to when it happened,
685+
* not now — so seed from its start. Live sessions and notes default to now. */
686+
function defaultDoseTime(): string {
687+
return selected?.kind === "session" && selected.ended_at
688+
? isoToLocalInput(selected.started_at)
689+
: nowLocalInput();
690+
}
691+
679692
async function openExperience(id: number) {
680693
lastWarnings = [];
681694
editExp = false;
682695
editingDoseId = null;
683696
dRef = null;
684697
exportErr = exportMsg = null;
685698
selected = await getExperience(id);
686-
dTime = nowLocalInput();
699+
dTime = defaultDoseTime();
687700
}
688701
689702
function openNewExp() {
@@ -692,6 +705,12 @@
692705
if (showNewExp && !neStart) neStart = nowLocalInput();
693706
}
694707
708+
// When "this already happened" is ticked, seed the end time from the start so
709+
// the field isn't empty — the person adjusts both to the real dates.
710+
function onPastToggle() {
711+
if (nePast && !neEnd) neEnd = neStart;
712+
}
713+
695714
function openNewNote() {
696715
showNewNote = !showNewNote;
697716
if (showNewNote) showNewExp = false;
@@ -792,13 +811,21 @@
792811
}
793812
794813
async function submitNewExperience() {
814+
const startIso = localInputToIso(neStart);
795815
const e = await createExperience({
796816
title: neTitle || "Untitled experience",
797817
intention: neIntention,
798818
setting: neSetting,
799-
started_at: localInputToIso(neStart),
819+
started_at: startIso,
800820
});
801-
neTitle = neIntention = neSetting = neStart = "";
821+
// A past experience is over the moment it's logged — mark it ended so it's
822+
// history, not a live session (no "ongoing", no live-session controls). If
823+
// the end time was left blank, fall back to the start rather than to now.
824+
if (nePast) {
825+
await endExperience(e.id, neEnd ? localInputToIso(neEnd) : startIso, null, "");
826+
}
827+
neTitle = neIntention = neSetting = neStart = neEnd = "";
828+
nePast = false;
802829
showNewExp = false;
803830
await loadJournal();
804831
await openExperience(e.id);
@@ -816,7 +843,7 @@
816843
});
817844
lastWarnings = res.warnings;
818845
dSubstance = dAmount = "";
819-
dTime = nowLocalInput();
846+
dTime = defaultDoseTime();
820847
await openExperienceKeepWarnings(selected.id);
821848
await loadJournal();
822849
}
@@ -1076,6 +1103,19 @@
10761103
let fbSummary = $state("");
10771104
let fbDetail = $state("");
10781105
1106+
// A quick way in from the header, so reporting a bug isn't buried in Settings.
1107+
let showFeedback = $state(false);
1108+
function openBugReport() {
1109+
fbKind = "bug";
1110+
showFeedback = true;
1111+
}
1112+
// From the modal: open the prefilled issue, then close. (The Settings card
1113+
// calls openFeedback directly and stays put.)
1114+
async function sendFeedback() {
1115+
await openFeedback();
1116+
showFeedback = false;
1117+
}
1118+
10791119
async function openFeedback() {
10801120
const isBug = fbKind === "bug";
10811121
let version = "";
@@ -1623,6 +1663,7 @@
16231663
<button class:active={tab === "substances"} onclick={() => goTab("substances")}>Substances</button>
16241664
<button class:active={tab === "bysub"} onclick={() => goTab("bysub")}>Substance Log</button>
16251665
<button class:active={tab === "data"} onclick={() => goTab("data")}>Settings</button>
1666+
<button title="Report a bug or request a feature" onclick={openBugReport}>🐛 Report a bug</button>
16261667
<button title="Emergency &amp; support resources" onclick={openHelp}>Emergency Resources</button>
16271668
</nav>
16281669
</header>
@@ -1819,11 +1860,18 @@
18191860
{#if showNewExp}
18201861
<div class="new-exp">
18211862
<input placeholder="Title" bind:value={neTitle} />
1822-
<input type="datetime-local" bind:value={neStart} title="Start time" />
1863+
<input type="datetime-local" bind:value={neStart} title={nePast ? "When it started" : "Start time"} />
1864+
{#if nePast}
1865+
<input type="datetime-local" bind:value={neEnd} title="When it ended (optional)" />
1866+
{/if}
18231867
<input placeholder="Intention (optional)" bind:value={neIntention} />
18241868
<input placeholder="Set & setting (optional)" bind:value={neSetting} />
1825-
<button class="primary small-btn" onclick={submitNewExperience}>Start</button>
1869+
<button class="primary small-btn" onclick={submitNewExperience}>{nePast ? "Log it" : "Start"}</button>
18261870
</div>
1871+
<label class="past-toggle">
1872+
<input type="checkbox" bind:checked={nePast} onchange={onPastToggle} />
1873+
This already happened — I'm logging a past experience
1874+
</label>
18271875
{/if}
18281876

18291877
{#if showNewNote}
@@ -2663,6 +2711,39 @@ Peak was intense and connected; gentle comedown by 1am. Drank lots of water, no
26632711
</div>
26642712
{/if}
26652713

2714+
{#if showFeedback}
2715+
<!-- svelte-ignore a11y_click_events_have_key_events -->
2716+
<div class="modal-overlay" role="presentation" onclick={() => (showFeedback = false)}>
2717+
<!-- svelte-ignore a11y_click_events_have_key_events -->
2718+
<div class="help-modal" role="dialog" aria-modal="true" tabindex="-1" onclick={(e) => e.stopPropagation()}>
2719+
<h2>{fbKind === "bug" ? "Report a bug" : "Request a feature"}</h2>
2720+
<p class="muted small">
2721+
Opens a prefilled issue on GitHub in your browser — nothing leaves your journal; you
2722+
write and send it there.
2723+
</p>
2724+
<div class="fb-kind">
2725+
<label><input type="radio" bind:group={fbKind} value="bug" /> Report a bug</label>
2726+
<label><input type="radio" bind:group={fbKind} value="feature" /> Request a feature</label>
2727+
</div>
2728+
<input
2729+
class="fb-field"
2730+
placeholder={fbKind === "bug" ? "What went wrong? (short summary)" : "What would you like? (short summary)"}
2731+
bind:value={fbSummary}
2732+
/>
2733+
<textarea
2734+
class="fb-field"
2735+
rows="3"
2736+
placeholder="Any detail you want to include (optional — you can also write it on GitHub)"
2737+
bind:value={fbDetail}
2738+
></textarea>
2739+
<div class="row-actions">
2740+
<button class="ghost small-btn" onclick={() => (showFeedback = false)}>Cancel</button>
2741+
<button class="primary small-btn" onclick={sendFeedback}>Continue on GitHub →</button>
2742+
</div>
2743+
</div>
2744+
</div>
2745+
{/if}
2746+
26662747
<!-- ============ LIVE SESSION ============ -->
26672748
{#if liveSession && selected}
26682749
<div class="live">
@@ -2821,6 +2902,8 @@ Peak was intense and connected; gentle comedown by 1am. Drank lots of water, no
28212902
28222903
.new-exp, .dose-form, .new-sub { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0.8rem 0; align-items: center; }
28232904
.new-exp input, .new-sub input { flex: 1; min-width: 8rem; }
2905+
.past-toggle { display: flex; align-items: center; gap: 0.45rem; margin: -0.3rem 0 0.8rem; color: var(--muted); font-size: 0.85rem; cursor: pointer; }
2906+
.past-toggle input { cursor: pointer; }
28242907
.new-note { display: flex; flex-direction: column; gap: 0.5rem; margin: 0.8rem 0; }
28252908
.new-note textarea { width: 100%; resize: vertical; }
28262909
.note-pill { font-style: italic; }

0 commit comments

Comments
 (0)