feat: add web push and sadhna tracker
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
// SadhnaLog is one persisted row of the sadhna_logs table — the chanting
|
||||
// half of a day's sādhana. The posting half is derived from the posts
|
||||
// table at read time, so it has no column here.
|
||||
type SadhnaLog struct {
|
||||
ID string `json:"id"`
|
||||
UserID string `json:"user_id"`
|
||||
LogDate time.Time `json:"log_date"`
|
||||
RoundsCompleted int `json:"rounds_completed"`
|
||||
ChantDone bool `json:"chant_done"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// SadhnaDay is one cell of the 7-day streak strip. `Completed` is the
|
||||
// conjunction the streak counts: both the chanting and the posting were
|
||||
// done that calendar day.
|
||||
type SadhnaDay struct {
|
||||
Date string `json:"date"` // YYYY-MM-DD (UTC)
|
||||
ChantDone bool `json:"chant_done"`
|
||||
QuoteDone bool `json:"quote_done"`
|
||||
Completed bool `json:"completed"`
|
||||
}
|
||||
|
||||
// VineDay is one fold of the sādhana creeper — one day of practice the
|
||||
// vine has wound around its pole. The creeper grows a fresh fold for each
|
||||
// day of the current streak (oldest first), plus a final in-progress fold
|
||||
// for an unfinished today. Rounds/Posts annotate the fold so the devotee
|
||||
// sees exactly what they offered that day.
|
||||
type VineDay struct {
|
||||
Date string `json:"date"` // YYYY-MM-DD (UTC)
|
||||
Rounds int `json:"rounds"` // rounds chanted that day
|
||||
Posts int `json:"posts"` // quotes posted that day
|
||||
Completed bool `json:"completed"` // both disciplines done (a full fold)
|
||||
InProgress bool `json:"in_progress"` // today, not yet complete (the growing tip)
|
||||
}
|
||||
|
||||
// SadhnaReward is one gift item in the streak-reward catalog.
|
||||
type SadhnaReward struct {
|
||||
ID string `json:"id"`
|
||||
Key string `json:"key"`
|
||||
Name string `json:"name"`
|
||||
Meaning string `json:"meaning"`
|
||||
ImageURL string `json:"image_url"`
|
||||
Active bool `json:"active"`
|
||||
Sort int `json:"sort"`
|
||||
}
|
||||
|
||||
// SadhnaRewardGrant is a reward a user earned at a streak milestone (a
|
||||
// multiple of 7 days). The full reward is embedded for direct rendering.
|
||||
type SadhnaRewardGrant struct {
|
||||
Milestone int `json:"milestone"`
|
||||
GrantedAt time.Time `json:"granted_at"`
|
||||
Reward SadhnaReward `json:"reward"`
|
||||
}
|
||||
|
||||
// SadhnaDashboard is the single payload the /sadhna-streak page reads. It
|
||||
// folds together today's progress, the week strip, the streak counters,
|
||||
// and the plant's growth state so the client renders without further
|
||||
// round-trips.
|
||||
type SadhnaDashboard struct {
|
||||
// Today's two disciplines.
|
||||
TargetRounds int `json:"target_rounds"` // user's goal (16 if unset)
|
||||
RoundsCompleted int `json:"rounds_completed"` // saved progress today
|
||||
ChantDone bool `json:"chant_done"` // rounds reached target
|
||||
QuoteDone bool `json:"quote_done"` // posted at least one quote today
|
||||
TodayCompleted bool `json:"today_completed"` // both done today
|
||||
|
||||
// Streak counters.
|
||||
CurrentStreak int `json:"current_streak"`
|
||||
LongestStreak int `json:"longest_streak"`
|
||||
|
||||
// Plant state. Growth is 0–100; Stage is the derived label the client
|
||||
// maps to a visual; Alive is false only when growth has decayed to 0.
|
||||
Growth int `json:"growth"`
|
||||
Stage string `json:"stage"` // dead | sprout | seedling | sapling | young | mature
|
||||
Alive bool `json:"alive"`
|
||||
|
||||
// The trailing 7 calendar days, oldest first, for the top strip.
|
||||
Week []SadhnaDay `json:"week"`
|
||||
|
||||
// The creeper: one fold per day of the current streak (oldest first),
|
||||
// plus a final in-progress fold for an unfinished today. Capped to the
|
||||
// most recent vineMaxDays folds for payload sanity; CurrentStreak holds
|
||||
// the true length.
|
||||
VineDays []VineDay `json:"vine_days"`
|
||||
|
||||
// Rewards. NextRewardDate is the projected UTC date (YYYY-MM-DD) the next
|
||||
// gift lands if the streak continues — for the calendar's gift marker.
|
||||
// PendingReward is a freshly earned, not-yet-celebrated gift the client
|
||||
// should celebrate now (nil when there's nothing to show).
|
||||
NextRewardDate *string `json:"next_reward_date"`
|
||||
PendingReward *SadhnaRewardGrant `json:"pending_reward"`
|
||||
}
|
||||
@@ -171,3 +171,12 @@ type Notification struct {
|
||||
ActorHandle *string `json:"actor_handle,omitempty"`
|
||||
ActorAvatar *string `json:"actor_avatar_url,omitempty"`
|
||||
}
|
||||
|
||||
// PushSubscription is one browser/device Web Push endpoint a user granted.
|
||||
type PushSubscription struct {
|
||||
ID string `json:"id"`
|
||||
UserID string `json:"user_id"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
P256dh string `json:"p256dh"`
|
||||
Auth string `json:"auth"`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user