1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
2//
3// SPDX-License-Identifier: AGPL-3.0-or-later
4
5package lunatask
6
7import (
8 "context"
9 "net/http"
10 "time"
11)
12
13// JournalEntry is a daily journal entry. Name and Content are encrypted
14// client-side and will be null when read back from the API.
15type JournalEntry struct {
16 ID string `json:"id"`
17 DateOn Date `json:"date_on"`
18 CreatedAt time.Time `json:"created_at"`
19 UpdatedAt time.Time `json:"updated_at"`
20}
21
22// createJournalEntryRequest defines a new journal entry for JSON serialization.
23type createJournalEntryRequest struct {
24 // DateOn is the date for the journal entry (required).
25 DateOn Date `json:"date_on"`
26 // Name is the title for the entry (optional, defaults to weekday name like "Tuesday, July 1st").
27 Name *string `json:"name,omitempty"`
28 // Content is the Markdown content of the entry (optional).
29 Content *string `json:"content,omitempty"`
30}
31
32// journalEntryResponse wraps a single journal entry from the API.
33type journalEntryResponse struct {
34 JournalEntry JournalEntry `json:"journal_entry"`
35}
36
37// JournalEntryBuilder constructs and creates a journal entry via method chaining.
38// Journal content is encrypted client-side; the API accepts it on create but
39// returns null on read.
40//
41// entry, err := lunatask.NewJournalEntry(lunatask.Today()).
42// WithContent("Shipped the new feature!").
43// Create(ctx, client)
44type JournalEntryBuilder struct {
45 req createJournalEntryRequest
46}
47
48// NewJournalEntry starts building a journal entry for the given date.
49func NewJournalEntry(date Date) *JournalEntryBuilder {
50 return &JournalEntryBuilder{req: createJournalEntryRequest{DateOn: date}} //nolint:exhaustruct
51}
52
53// WithName sets the entry's title. Defaults to the weekday name if omitted.
54func (b *JournalEntryBuilder) WithName(name string) *JournalEntryBuilder {
55 b.req.Name = &name
56
57 return b
58}
59
60// WithContent sets the Markdown body.
61func (b *JournalEntryBuilder) WithContent(content string) *JournalEntryBuilder {
62 b.req.Content = &content
63
64 return b
65}
66
67// Create sends the journal entry to Lunatask. Returns the created entry's metadata;
68// Name and Content won't round-trip due to E2EE.
69func (b *JournalEntryBuilder) Create(ctx context.Context, c *Client) (*JournalEntry, error) {
70 resp, _, err := doJSON[journalEntryResponse](ctx, c, http.MethodPost, "/journal_entries", b.req)
71 if err != nil {
72 return nil, err
73 }
74
75 return &resp.JournalEntry, nil
76}