Skip to content

Commit 634f25e

Browse files
committed
Merge branch 'pwa_fixes_2' of https://github.com/ByteBard11/sure into pwa_fixes_2
2 parents cac542e + f61ad18 commit 634f25e

File tree

167 files changed

+5252
-402
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

167 files changed

+5252
-402
lines changed

.cursor/rules/general-rules.mdc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ alwaysApply: true
1111
- Read [project-design.mdc](mdc:.cursor/rules/project-design.mdc) to understand the codebase
1212
- Read [project-conventions.mdc](mdc:.cursor/rules/project-conventions.mdc) to understand _how_ to write code for the codebase
1313
- Read [ui-ux-design-guidelines.mdc](mdc:.cursor/rules/ui-ux-design-guidelines.mdc) to understand how to implement frontend code specifically
14-
- Ignore i18n methods and files. Hardcode strings in English for now to optimize speed of development.
1514
- ActiveRecord migrations must inherit from `ActiveRecord::Migration[7.2]`. Do **not** use version 8.0 yet.
1615

1716
## Prohibited actions

.devcontainer/devcontainer.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
"name": "Sure",
33
"dockerComposeFile": "docker-compose.yml",
44
"service": "app",
5+
"runServices": [
6+
"db",
7+
"redis"
8+
],
59
"workspaceFolder": "/workspace",
610
"containerEnv": {
711
"GIT_EDITOR": "code --wait",

.env.example

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
# Enables self hosting features (should be set to true unless you know what you're doing)
1111
SELF_HOSTED=true
1212

13+
# Controls onboarding flow (valid: open, closed, invite_only)
14+
ONBOARDING_STATE=open
15+
1316
# Secret key used to encrypt credentials (https://api.rubyonrails.org/v7.1.3.2/classes/Rails/Application.html#method-i-secret_key_base)
1417
# Has to be a random string, generated eg. by running `openssl rand -hex 64`
1518
SECRET_KEY_BASE=secret-value
@@ -32,10 +35,15 @@ LANGFUSE_SECRET_KEY=
3235
# Get it here: https://twelvedata.com/
3336
TWELVE_DATA_API_KEY=
3437

35-
# Optional: Twelve Data provider is the default for exchange rates and securities.
38+
# Optional: Provider selection for exchange rates and securities data
39+
# Options: twelve_data (default), yahoo_finance
3640
EXCHANGE_RATE_PROVIDER=twelve_data
3741
SECURITIES_PROVIDER=twelve_data
3842

43+
# Alternative: Use Yahoo Finance as provider (free, no API key required)
44+
# EXCHANGE_RATE_PROVIDER=yahoo_finance
45+
# SECURITIES_PROVIDER=yahoo_finance
46+
3947
# Custom port config
4048
# For users who have other applications listening at 3000, this allows them to set a value puma will listen to.
4149
PORT=3000
@@ -107,3 +115,12 @@ BRAND_NAME=
107115
# CLOUDFLARE_SECRET_ACCESS_KEY=
108116
# CLOUDFLARE_BUCKET=
109117
#
118+
# Generic S3
119+
# ==========
120+
# ACTIVE_STORAGE_SERVICE=generic_s3 <- Enables Generic S3 storage
121+
# GENERIC_S3_ACCESS_KEY_ID=
122+
# GENERIC_S3_SECRET_ACCESS_KEY=
123+
# GENERIC_S3_REGION=
124+
# GENERIC_S3_BUCKET=
125+
# GENERIC_S3_ENDPOINT=
126+
# GENERIC_S3_FORCE_PATH_STYLE= <- defaults to false

.env.local.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# To enable / disable self-hosting features.
22
SELF_HOSTED = true
33

4+
# Controls onboarding flow (valid: open, closed, invite_only)
5+
ONBOARDING_STATE = open
6+
47
# Enable Twelve market data (careful, this will use your API credits)
58
TWELVE_DATA_API_KEY =
69

.env.test.example

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
SELF_HOSTED=false
22

3+
# Controls onboarding flow (valid: open, closed, invite_only)
4+
ONBOARDING_STATE=open
5+
36
# OpenID Connect for tests
47
OIDC_ISSUER=
58
OIDC_CLIENT_ID=
@@ -21,4 +24,4 @@ OIDC_REDIRECT_URI=http://localhost:3000/auth/openid_connect/callback
2124
COVERAGE=false
2225

2326
# Set to true to run test suite serially
24-
DISABLE_PARALLELIZATION=false
27+
DISABLE_PARALLELIZATION=false

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
/tmp/storage/*
3131
!/tmp/storage/
3232
!/tmp/storage/.keep
33+
/db/development.sqlite3
3334

3435
/public/assets
3536

@@ -106,3 +107,6 @@ scripts/
106107
.windsurfrules
107108
.cursor/rules/dev_workflow.mdc
108109
.cursor/rules/taskmaster.mdc
110+
111+
# Local Junie helpers
112+
.junie/

CLAUDE.md

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,7 @@ Only proceed with pull request creation if ALL checks pass.
5656
- Use `Current.family` for the current family. Do NOT use `current_family`.
5757

5858
### Development Guidelines
59-
- Prior to generating any code, carefully read the project conventions and guidelines
60-
- Ignore i18n methods and files. Hardcode strings in English for now to optimize speed of development
59+
- Carefully read project conventions and guidelines before generating any code.
6160
- Do not run `rails server` in your responses
6261
- Do not run `touch tmp/restart.txt`
6362
- Do not run `rails credentials`
@@ -112,6 +111,15 @@ Sidekiq handles asynchronous tasks:
112111
- Always use functional tokens (e.g., `text-primary` not `text-white`)
113112
- Prefer semantic HTML elements over JS components
114113
- Use `icon` helper for icons, never `lucide_icon` directly
114+
- **i18n**: All user-facing strings must use localization (i18n). Update locale files for each new or changed element.
115+
116+
### Internationalization (i18n) Guidelines
117+
- **Key Organization**: Use hierarchical keys by feature: `accounts.index.title`, `transactions.form.amount_label`
118+
- **Translation Helper**: Always use `t()` helper for user-facing strings
119+
- **Interpolation**: Use for dynamic content: `t("users.greeting", name: user.name)`
120+
- **Pluralization**: Use Rails pluralization: `t("transactions.count", count: @transactions.count)`
121+
- **Locale Files**: Update `config/locales/en.yml` for new strings
122+
- **Missing Translations**: Configure to raise errors in development for missing keys
115123

116124
### Multi-Currency Support
117125
- All monetary values stored in base currency (user's primary currency)
@@ -220,11 +228,36 @@ Sidekiq handles asynchronous tasks:
220228
```erb
221229
<!-- GOOD: Declarative - HTML declares what happens -->
222230
<div data-controller="toggle">
223-
<button data-action="click->toggle#toggle" data-toggle-target="button">Show</button>
224-
<div data-toggle-target="content" class="hidden">Hello World!</div>
231+
<button data-action="click->toggle#toggle" data-toggle-target="button">
232+
<%= t("components.transaction_details.show_details") %>
233+
</button>
234+
<div data-toggle-target="content" class="hidden">
235+
<p><%= t("components.transaction_details.amount_label") %>: <%= @transaction.amount %></p>
236+
<p><%= t("components.transaction_details.date_label") %>: <%= @transaction.date %></p>
237+
<p><%= t("components.transaction_details.category_label") %>: <%= @transaction.category.name %></p>
238+
</div>
225239
</div>
226240
```
227241

242+
**Example locale file structure (config/locales/en.yml):**
243+
```yaml
244+
en:
245+
components:
246+
transaction_details:
247+
show_details: "Show Details"
248+
hide_details: "Hide Details"
249+
amount_label: "Amount"
250+
date_label: "Date"
251+
category_label: "Category"
252+
```
253+
254+
**i18n Best Practices:**
255+
- Organize keys by feature/component: `components.transaction_details.show_details`
256+
- Use descriptive key names that indicate purpose: `show_details` not `button`
257+
- Group related translations together in the same namespace
258+
- Use interpolation for dynamic content: `t("users.welcome", name: user.name)`
259+
- Always update locale files when adding new user-facing strings
260+
228261
**Controller Best Practices:**
229262
- Keep controllers lightweight and simple (< 7 targets)
230263
- Use private methods and expose clear public API

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,9 @@ For further instructions, see guides below.
8686
- [Windows dev setup](https://github.com/we-promise/sure/wiki/Windows-Dev-Setup-Guide)
8787
- Dev containers - visit [this guide](https://code.visualstudio.com/docs/devcontainers/containers)
8888

89-
### One click deploys
89+
### One-click
90+
91+
[![Run on PikaPods](https://www.pikapods.com/static/run-button.svg)](https://www.pikapods.com/pods?run=maybe)
9092

9193
[![Deploy on Railway](https://railway.com/button.svg)](https://railway.com/deploy/sure?referralCode=CW_fPQ)
9294

app/components/UI/account/activity_feed.html.erb

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
<%= turbo_frame_tag dom_id(account, "entries") do %>
22
<div class="bg-container p-5 shadow-border-xs rounded-xl">
33
<div class="flex items-center justify-between mb-4" data-testid="activity-menu">
4-
<%= tag.h2 "Activity", class: "font-medium text-lg" %>
4+
<%= tag.h2 t("accounts.show.activity.title"), class: "font-medium text-lg" %>
55

66
<% if account.manual? %>
77
<%= render DS::Menu.new(variant: "button") do |menu| %>
8-
<% menu.with_button(text: "New", variant: "secondary", icon: "plus") %>
8+
<% menu.with_button(text: t("accounts.show.activity.new"), variant: "secondary", icon: "plus") %>
99

1010
<% menu.with_item(
1111
variant: "link",
12-
text: "New balance",
12+
text: t("accounts.show.activity.new_balance"),
1313
icon: "circle-dollar-sign",
1414
href: new_valuation_path(account_id: account.id),
1515
data: { turbo_frame: :modal }) %>
1616

1717
<% unless account.crypto? %>
1818
<% menu.with_item(
1919
variant: "link",
20-
text: "New transaction",
20+
text: t("accounts.show.activity.new_transaction"),
2121
icon: "credit-card",
2222
href: account.investment? ? new_trade_path(account_id: account.id) : new_transaction_path(account_id: account.id),
2323
data: { turbo_frame: :modal }) %>
@@ -40,7 +40,7 @@
4040
<%= hidden_field_tag :account_id, account.id %>
4141

4242
<%= form.search_field :search,
43-
placeholder: "Search entries by name",
43+
placeholder: t("accounts.show.activity.search.placeholder"),
4444
value: search,
4545
class: "form-field__input placeholder:text-sm placeholder:text-secondary",
4646
"data-auto-submit-form-target": "auto" %>
@@ -51,7 +51,7 @@
5151
</div>
5252

5353
<% if activity_dates.empty? %>
54-
<p class="text-secondary text-sm p-4">No entries yet</p>
54+
<%= tag.p t("accounts.show.activity.no_entries"), class: "text-secondary text-sm p-4" %>
5555
<% else %>
5656
<%= tag.div id: dom_id(account, "entries_bulk_select"),
5757
data: {
@@ -68,10 +68,10 @@
6868
<%= check_box_tag "selection_entry",
6969
class: "checkbox checkbox--light",
7070
data: { action: "bulk-select#togglePageSelection" } %>
71-
<p>Date</p>
71+
<%= tag.p t("accounts.show.activity.date") %>
7272
</div>
7373

74-
<%= tag.p "Amount", class: "col-span-4 justify-self-end" %>
74+
<%= tag.p t("accounts.show.activity.amount"), class: "col-span-4 justify-self-end" %>
7575
</div>
7676

7777
<div>

app/controllers/accounts_controller.rb

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,17 @@ def show
2828

2929
def sync
3030
unless @account.syncing?
31-
@account.sync_later
31+
if @account.linked?
32+
# Sync all provider items for this account
33+
# Each provider item will trigger an account sync when complete
34+
@account.account_providers.each do |account_provider|
35+
item = account_provider.adapter&.item
36+
item&.sync_later if item && !item.syncing?
37+
end
38+
else
39+
# Manual accounts just need balance materialization
40+
@account.sync_later
41+
end
3242
end
3343

3444
redirect_to account_path(@account)

0 commit comments

Comments
 (0)