Files
study-bible-project/src/components/reader/PlanSheet.jsx
T
nmemmertandClaude Sonnet 5.5 b1bc1c8ea4
Build and Push Docker Image / build-and-push (push) Failing after 19s
Reading plans: integrated into the Reader, redesigned, with per-plan translation
Reader: plan strip with a dot per chapter, plan sheet (day picker, chapter
ticks, translation, streak, other plans), end-of-day card that steps through
the day and rolls into the next, and chapter-level auto-marking.
Each plan remembers its own translation (BSB, ESV, NLT, CSB, NASB, NET) and the
Reader follows it while a plan is open. Plans home redesigned in the reader's
themes with a Continue card, in-progress plans, a filterable catalog, and
sheets for details and the custom-plan builder.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-29 09:47:51 -04:00

76 lines
4.7 KiB
React

// The plan's control room, one tap from the reader: pick the day, tick chapters,
// choose the Bible this plan is read in, and jump to another active plan.
import Sheet from './Sheet.jsx';
import { ChevronLeft, ChevronRight, CheckIcon } from './icons.jsx';
import { READER_TRANSLATIONS } from '../../hooks/useBibleReader.js';
import { formatDayReadings } from '../../utils/readingPlans.js';
export default function PlanSheet({
open, onClose, info, translation, currentKey, streak, otherPlans, studyBusy,
onDay, onToggleChapter, onGoChapter, onTranslation, onToggleDay, onSwitchPlan, onListen, onStudy, onLeave,
}) {
if (!info) return null;
const label = (r) => formatDayReadings([r]);
return (
<Sheet open={open} onClose={onClose} title={info.plan.title}>
<div className="mb-1 flex items-center justify-between">
<button type="button" onClick={() => onDay(-1)} disabled={info.dayIndex <= 0} aria-label="Previous day"
className="rounded-lg p-1.5 text-[var(--r-sub)] hover:bg-black/5 disabled:opacity-30"><ChevronLeft /></button>
<span className="text-sm font-medium">Day {info.dayIndex + 1} of {info.plan.days}{info.done ? ' · read' : ''}</span>
<button type="button" onClick={() => onDay(1)} disabled={info.dayIndex >= info.plan.days - 1} aria-label="Next day"
className="rounded-lg p-1.5 text-[var(--r-sub)] hover:bg-black/5 disabled:opacity-30"><ChevronRight /></button>
</div>
<p className="mb-1 mt-3 text-[11px] uppercase tracking-wide text-[var(--r-sub)]">Reading</p>
{info.refs.map((r) => {
const key = `${r.book}.${r.chapter}`;
const read = info.readSet.has(key);
return (
<div key={key} className="flex items-center gap-3 border-b border-[var(--r-line)] py-2">
<button type="button" onClick={() => onToggleChapter(key)} aria-label={read ? 'Mark unread' : 'Mark read'}
className={`flex h-5 w-5 shrink-0 items-center justify-center rounded-full border-[1.5px] ${read ? 'border-[var(--r-accent)] bg-[var(--r-accent)] text-[var(--r-on)]' : 'border-[var(--r-sub)] text-transparent'}`}>
<span className="scale-75"><CheckIcon /></span>
</button>
<button type="button" onClick={() => onGoChapter(r)} className={`flex-1 text-left text-sm ${key === currentKey ? 'font-medium' : ''}`}>{label(r)}</button>
{key === currentKey && <span className="rounded-full border border-[var(--r-line)] px-2 py-0.5 text-[10px] text-[var(--r-sub)]">reading</span>}
</div>
);
})}
<button type="button" onClick={onToggleDay}
className="mt-3 w-full rounded-xl border border-[var(--r-line)] py-2 text-sm hover:bg-black/5">
{info.done ? 'Mark this day unread' : 'Mark the whole day read'}
</button>
<p className="mb-1 mt-4 text-[11px] uppercase tracking-wide text-[var(--r-sub)]">This plan</p>
<div className="flex items-center justify-between py-1.5 text-sm">
<span>Read in</span>
<select value={translation} onChange={(e) => onTranslation(e.target.value)}
className="rounded-lg border border-[var(--r-line)] bg-[var(--r-bg)] px-2 py-1 text-sm text-[var(--r-text)]">
{READER_TRANSLATIONS.map((t) => <option key={t.id} value={t.id}>{t.id} · {t.name}</option>)}
</select>
</div>
<div className="flex items-center justify-between py-1.5 text-sm">
<span>Streak</span><span className="text-[var(--r-sub)]">{streak.current} day{streak.current === 1 ? '' : 's'}</span>
</div>
<div className="mt-2 flex gap-2">
<button type="button" onClick={onListen} className="flex-1 rounded-xl border border-[var(--r-line)] py-2 text-sm hover:bg-black/5">Listen</button>
<button type="button" onClick={onStudy} disabled={studyBusy} className="flex-1 rounded-xl border border-[var(--r-line)] py-2 text-sm hover:bg-black/5 disabled:opacity-50">{studyBusy ? 'Building…' : 'Study this day'}</button>
</div>
{otherPlans.length > 0 && (
<>
<p className="mb-1 mt-4 text-[11px] uppercase tracking-wide text-[var(--r-sub)]">Other plans</p>
{otherPlans.map((o) => (
<button key={o.progress.id} type="button" onClick={() => onSwitchPlan(o)}
className="flex w-full items-center justify-between rounded-lg px-1 py-2 text-left text-sm hover:bg-black/5">
<span className="truncate">{o.plan.title}</span>
<span className="ml-3 shrink-0 text-xs text-[var(--r-sub)]">Day {o.dayIndex + 1}</span>
</button>
))}
</>
)}
<button type="button" onClick={onLeave} className="mt-4 w-full text-center text-xs text-[var(--r-sub)] underline">Leave plan (keep reading on my own)</button>
</Sheet>
);
}