├── .github └── FUNDING.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── android └── README.md ├── ios ├── .gitignore ├── App │ ├── Components │ │ ├── BridgeComponent+App.swift │ │ ├── ButtonComponent.swift │ │ ├── FormComponent.swift │ │ └── NavigationComponent.swift │ ├── Configuration │ │ └── Endpoint.swift │ ├── Delegates │ │ ├── AppDelegate.swift │ │ └── SceneDelegate.swift │ ├── Extensions │ │ └── UINavigationBar+Appearance.swift │ └── Resources │ │ ├── Assets.xcassets │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ ├── AppIcon.png │ │ │ └── Contents.json │ │ └── Contents.json │ │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ │ └── Info.plist ├── DailyLog.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── swiftpm │ │ └── Package.resolved └── README.md └── rails ├── .dockerignore ├── .gitattributes ├── .gitignore ├── .ruby-version ├── Dockerfile ├── Gemfile ├── Gemfile.lock ├── Procfile ├── Procfile.dev ├── README.md ├── Rakefile ├── app ├── assets │ ├── builds │ │ └── .keep │ ├── config │ │ └── manifest.js │ ├── images │ │ ├── .keep │ │ ├── app_store.png │ │ ├── github.svg │ │ ├── icons │ │ │ ├── mini │ │ │ │ ├── check_circle.svg │ │ │ │ ├── chevron_left.svg │ │ │ │ ├── chevron_right.svg │ │ │ │ ├── plus.svg │ │ │ │ └── x_circle.svg │ │ │ └── outline │ │ │ │ └── user_circle.svg │ │ ├── logo.svg │ │ └── screenshots │ │ │ └── ios.png │ └── stylesheets │ │ ├── application.css │ │ ├── application.tailwind.css │ │ └── strada.css ├── channels │ └── application_cable │ │ ├── channel.rb │ │ └── connection.rb ├── controllers │ ├── application_controller.rb │ ├── concerns │ │ ├── .keep │ │ ├── authentication.rb │ │ ├── has_date.rb │ │ └── honeybadger_context.rb │ ├── configurations_controller.rb │ ├── days_controller.rb │ ├── exercise_entries_controller.rb │ ├── food_entries_controller.rb │ ├── home_controller.rb │ ├── medication_entries_controller.rb │ ├── sessions_controller.rb │ ├── settings_controller.rb │ ├── users_controller.rb │ └── water_entries_controller.rb ├── helpers │ ├── analytics_helper.rb │ ├── application_helper.rb │ ├── date_helper.rb │ ├── form_helper.rb │ └── turbo_native_helper.rb ├── javascript │ ├── application.js │ └── controllers │ │ ├── application.js │ │ ├── bridge │ │ ├── button_controller.js │ │ ├── form_controller.js │ │ └── navigation_controller.js │ │ └── index.js ├── jobs │ └── application_job.rb ├── mailers │ └── application_mailer.rb ├── models │ ├── application_record.rb │ ├── concerns │ │ └── .keep │ ├── current.rb │ ├── exercise_entry.rb │ ├── food_entry.rb │ ├── medication_entry.rb │ ├── setting.rb │ ├── user.rb │ └── water_entry.rb ├── validators │ └── time_zone_validator.rb └── views │ ├── days │ ├── _navigation.html.erb │ ├── index.html.erb │ └── show.html.erb │ ├── exercise_entries │ ├── _form.html.erb │ ├── edit.html.erb │ └── new.html.erb │ ├── food_entries │ ├── _form.html.erb │ ├── edit.html.erb │ └── new.html.erb │ ├── home │ └── show.html.erb │ ├── layouts │ ├── application.html.erb │ ├── mailer.html.erb │ └── mailer.text.erb │ ├── medication_entries │ ├── _form.html.erb │ ├── edit.html.erb │ └── new.html.erb │ ├── sessions │ └── new.html.erb │ ├── settings │ └── edit.html.erb │ ├── shared │ ├── _flash.html.erb │ ├── _header.html.erb │ └── components │ │ ├── _list.html.erb │ │ ├── form │ │ └── _errors.html.erb │ │ └── list │ │ ├── _header.html.erb │ │ └── _item.html.erb │ ├── users │ └── new.html.erb │ └── water_entries │ └── new.html.erb ├── bin ├── bundle ├── dev ├── docker-entrypoint ├── importmap ├── rails ├── rake └── setup ├── config.ru ├── config ├── application.rb ├── boot.rb ├── cable.yml ├── credentials │ └── production.yml.enc ├── database.yml ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ └── test.rb ├── fathom.yml ├── honeybadger.yml ├── importmap.rb ├── initializers │ ├── assets.rb │ ├── date_formats.rb │ └── filter_parameter_logging.rb ├── puma.rb ├── routes.rb ├── storage.yml └── tailwind.config.js ├── db ├── migrate │ ├── 20231205220854_create_initial_tables.rb │ ├── 20231206182611_create_users.rb │ ├── 20231206191045_associate_entries_with_users.rb │ ├── 20231208012710_encrypt_sensitive_data.rb │ ├── 20231211184500_add_settings.rb │ ├── 20231212203056_add_units.rb │ └── 20231213145459_remove_amount_from_water_entries.rb ├── schema.rb └── seeds.rb ├── lib ├── assets │ └── .keep └── tasks │ └── .keep ├── log └── .keep ├── public ├── 404.html ├── 422.html ├── 500.html ├── apple-touch-icon-precomposed.png ├── apple-touch-icon.png ├── favicon.ico └── robots.txt ├── storage └── .keep ├── test ├── application_system_test_case.rb ├── channels │ └── .keep ├── controllers │ └── .keep ├── fixtures │ └── files │ │ └── .keep ├── helpers │ └── .keep ├── integration │ └── .keep ├── mailers │ └── .keep ├── models │ └── .keep ├── system │ └── .keep └── test_helper.rb ├── tmp ├── .keep ├── pids │ └── .keep └── storage │ └── .keep └── vendor ├── .keep └── javascript └── .keep /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: joemasilotti 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ios-swiftui/ 2 | notes.md 3 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of conduct 2 | 3 | ## Our pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | [joe@masilotti.com](mailto:joe@masilotti.com). All complaints will be reviewed 64 | and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | [https://www.contributor-covenant.org/version/2/0/code_of_conduct.html](https://www.contributor-covenant.org/version/2/0/code_of_conduct.html). 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | [https://www.contributor-covenant.org/faq](https://www.contributor-covenant.org/faq) 128 | . Translations are available at 129 | [https://www.contributor-covenant.org/translations](https://www.contributor-covenant.org/translations) 130 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Joe Masilotti 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Daily Log 2 | 3 | A Rails, iOS, and (upcoming) Android app to track my daily habits like exercise, medication, food, and water. 4 | 5 | > [!TIP] 6 | > Check out the app on the web at [dailylog.ing](https://dailylog.ing) or the [App Store](https://apps.apple.com/us/app/daily-log-app/id6473819686). 7 | 8 | At its core, Daily Log is a Ruby on Rails web application. It uses [Turbo Native](https://masilotti.com/turbo-ios/) to render web content in the mobile apps, "wrapping" the screens in native chrome. This approach unlocks native transitions between screens, native navigation buttons, and modals/sheets for data entry. 9 | 10 | ![Screenshots of the Daily Log mobile app](https://github.com/joemasilotti/daily-log/assets/2092156/a5d15dca-fb5a-4cf9-b031-3777cbf92e0f) 11 | -------------------------------------------------------------------------------- /android/README.md: -------------------------------------------------------------------------------- 1 | # Daily Log Android app 2 | 3 | > [!NOTE] 4 | > Coming soon! 5 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | # User settings 2 | xcuserdata/ 3 | -------------------------------------------------------------------------------- /ios/App/Components/BridgeComponent+App.swift: -------------------------------------------------------------------------------- 1 | import HotwireNative 2 | 3 | extension BridgeComponent { 4 | static var allTypes: [BridgeComponent.Type] { 5 | [ 6 | ButtonComponent.self, 7 | FormComponent.self, 8 | NavigationComponent.self 9 | ] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ios/App/Components/ButtonComponent.swift: -------------------------------------------------------------------------------- 1 | import HotwireNative 2 | import UIKit 3 | 4 | final class ButtonComponent: BridgeComponent { 5 | override class var name: String { "button" } 6 | 7 | override func onReceive(message: Message) { 8 | guard let viewController else { return } 9 | addButton(via: message, to: viewController) 10 | } 11 | 12 | private var viewController: UIViewController? { 13 | delegate.destination as? UIViewController 14 | } 15 | 16 | private func addButton(via message: Message, to viewController: UIViewController) { 17 | guard let data: MessageData = message.data() else { return } 18 | 19 | let image = UIImage(systemName: data.image) 20 | let action = UIAction { [unowned self] _ in 21 | self.reply(to: "connect") 22 | } 23 | let item = UIBarButtonItem(title: data.title, image: image, primaryAction: action) 24 | 25 | if data.side == "right" { 26 | viewController.navigationItem.rightBarButtonItem = item 27 | } else { 28 | viewController.navigationItem.leftBarButtonItem = item 29 | } 30 | } 31 | } 32 | 33 | private extension ButtonComponent { 34 | struct MessageData: Decodable { 35 | let title: String 36 | let image: String 37 | let side: String 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ios/App/Components/FormComponent.swift: -------------------------------------------------------------------------------- 1 | import HotwireNative 2 | import UIKit 3 | 4 | final class FormComponent: BridgeComponent { 5 | override class var name: String { "form" } 6 | 7 | override func onReceive(message: Message) { 8 | guard let event = Event(rawValue: message.event) else { return } 9 | 10 | switch event { 11 | case .connect: 12 | handleConnectEvent(message: message) 13 | case .submitEnabled: 14 | enableButton() 15 | case .submitDisabled: 16 | disableButton() 17 | } 18 | } 19 | 20 | private weak var button: UIBarButtonItem? 21 | private var viewController: UIViewController? { 22 | delegate.destination as? UIViewController 23 | } 24 | 25 | private func handleConnectEvent(message: Message) { 26 | guard let data: MessageData = message.data() else { return } 27 | configureButton(with: data.submitTitle) 28 | } 29 | 30 | private func enableButton() { 31 | button?.isEnabled = true 32 | } 33 | 34 | private func disableButton() { 35 | button?.isEnabled = false 36 | } 37 | 38 | private func configureButton(with title: String) { 39 | guard let viewController else { return } 40 | 41 | let action = UIAction(title: title) { [unowned self] _ in 42 | self.reply(to: Event.connect.rawValue) 43 | } 44 | 45 | let button = UIBarButtonItem(primaryAction: action) 46 | viewController.navigationItem.rightBarButtonItem = button 47 | self.button = button 48 | } 49 | } 50 | 51 | private extension FormComponent { 52 | enum Event: String { 53 | case connect 54 | case submitEnabled 55 | case submitDisabled 56 | } 57 | } 58 | 59 | private extension FormComponent { 60 | struct MessageData: Decodable { 61 | let submitTitle: String 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /ios/App/Components/NavigationComponent.swift: -------------------------------------------------------------------------------- 1 | import HotwireNative 2 | import UIKit 3 | 4 | class NavigationComponent: BridgeComponent { 5 | override class var name: String { "navigation" } 6 | 7 | override func onReceive(message: Message) { 8 | guard let viewController else { return } 9 | 10 | if message.event == "previous" { 11 | addPreviousButton(to: viewController) 12 | } else if message.event == "next" { 13 | addNextButton(to: viewController) 14 | } 15 | } 16 | 17 | private var viewController: UIViewController? { 18 | delegate.destination as? UIViewController 19 | } 20 | 21 | private func addPreviousButton(to viewController: UIViewController) { 22 | let image = UIImage(systemName: "chevron.forward.circle") 23 | let action = UIAction { [unowned self] _ in 24 | self.reply(to: "next") 25 | } 26 | let item = UIBarButtonItem(image: image, primaryAction: action) 27 | addBarButtonItem(item, to: viewController) 28 | } 29 | 30 | private func addNextButton(to viewController: UIViewController) { 31 | let image = UIImage(systemName: "chevron.backward.circle") 32 | let action = UIAction { [unowned self] _ in 33 | self.reply(to: "previous") 34 | } 35 | let item = UIBarButtonItem(image: image, primaryAction: action) 36 | addBarButtonItem(item, to: viewController) 37 | } 38 | 39 | private func addBarButtonItem(_ item: UIBarButtonItem, to viewController: UIViewController) { 40 | var items = viewController.navigationItem.rightBarButtonItems ?? [UIBarButtonItem]() 41 | guard items.count < 2 else { return } 42 | 43 | items.append(item) 44 | viewController.navigationItem.rightBarButtonItems = items 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /ios/App/Configuration/Endpoint.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | enum Endpoint { 4 | static var rootURL: URL { 5 | #if DEBUG 6 | return URL(string: "http://localhost:3000")! 7 | #else 8 | return URL(string: "https://dailylog.ing")! 9 | #endif 10 | } 11 | 12 | static var pathConfigurationURL: URL { 13 | rootURL.appending(path: "configurations/ios.json") 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ios/App/Delegates/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | @main 4 | class AppDelegate: UIResponder, UIApplicationDelegate {} 5 | -------------------------------------------------------------------------------- /ios/App/Delegates/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | import HotwireNative 2 | import UIKit 3 | 4 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 5 | var window: UIWindow? 6 | 7 | private lazy var navigator = Navigator(pathConfiguration: pathConfiguration) 8 | private let pathConfiguration = PathConfiguration(sources: [ 9 | .server(Endpoint.pathConfigurationURL) 10 | ]) 11 | 12 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 13 | UINavigationBar.configureWithOpaqueBackground() 14 | 15 | Hotwire.config.pathConfiguration.matchQueryStrings = false 16 | Hotwire.registerBridgeComponents(BridgeComponent.allTypes) 17 | 18 | window?.rootViewController = navigator.rootViewController 19 | navigator.route(Endpoint.rootURL) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ios/App/Extensions/UINavigationBar+Appearance.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | extension UINavigationBar { 4 | static func configureWithOpaqueBackground() { 5 | let navigationBarAppearance = UINavigationBarAppearance() 6 | navigationBarAppearance.configureWithOpaqueBackground() 7 | appearance().scrollEdgeAppearance = navigationBarAppearance 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /ios/App/Resources/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "136", 9 | "green" : "148", 10 | "red" : "13" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ios/App/Resources/Assets.xcassets/AppIcon.appiconset/AppIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joemasilotti/daily-log/2458b5bd901b656fe9e9874c9cdb815c5b0a930c/ios/App/Resources/Assets.xcassets/AppIcon.appiconset/AppIcon.png -------------------------------------------------------------------------------- /ios/App/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "AppIcon.png", 5 | "idiom" : "universal", 6 | "platform" : "ios", 7 | "size" : "1024x1024" 8 | } 9 | ], 10 | "info" : { 11 | "author" : "xcode", 12 | "version" : 1 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ios/App/Resources/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ios/App/Resources/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /ios/App/Resources/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /ios/App/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIApplicationSceneManifest 6 | 7 | UIApplicationSupportsMultipleScenes 8 | 9 | UISceneConfigurations 10 | 11 | UIWindowSceneSessionRoleApplication 12 | 13 | 14 | UISceneConfigurationName 15 | Default Configuration 16 | UISceneDelegateClassName 17 | $(PRODUCT_MODULE_NAME).SceneDelegate 18 | UISceneStoryboardFile 19 | Main 20 | 21 | 22 | 23 | 24 | ITSAppUsesNonExemptEncryption 25 | 26 | UIUserInterfaceStyle 27 | Light 28 | 29 | 30 | -------------------------------------------------------------------------------- /ios/DailyLog.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 70; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 84565F492CE7921C0074DFDA /* HotwireNative in Frameworks */ = {isa = PBXBuildFile; productRef = 84565F482CE7921C0074DFDA /* HotwireNative */; }; 11 | /* End PBXBuildFile section */ 12 | 13 | /* Begin PBXFileReference section */ 14 | 848871002CE7CFEC00651A1C /* Daily Log.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Daily Log.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 15 | /* End PBXFileReference section */ 16 | 17 | /* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ 18 | 84565F462CE791B90074DFDA /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = { 19 | isa = PBXFileSystemSynchronizedBuildFileExceptionSet; 20 | membershipExceptions = ( 21 | Resources/Info.plist, 22 | ); 23 | target = 84DE939C2B202F62006BDECB /* DailyLog */; 24 | }; 25 | /* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ 26 | 27 | /* Begin PBXFileSystemSynchronizedRootGroup section */ 28 | 84565F372CE791B90074DFDA /* App */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (84565F462CE791B90074DFDA /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = App; sourceTree = ""; }; 29 | /* End PBXFileSystemSynchronizedRootGroup section */ 30 | 31 | /* Begin PBXFrameworksBuildPhase section */ 32 | 84DE939A2B202F62006BDECB /* Frameworks */ = { 33 | isa = PBXFrameworksBuildPhase; 34 | buildActionMask = 2147483647; 35 | files = ( 36 | 84565F492CE7921C0074DFDA /* HotwireNative in Frameworks */, 37 | ); 38 | runOnlyForDeploymentPostprocessing = 0; 39 | }; 40 | /* End PBXFrameworksBuildPhase section */ 41 | 42 | /* Begin PBXGroup section */ 43 | 84DE93942B202F62006BDECB = { 44 | isa = PBXGroup; 45 | children = ( 46 | 84565F372CE791B90074DFDA /* App */, 47 | 848871002CE7CFEC00651A1C /* Daily Log.app */, 48 | ); 49 | sourceTree = ""; 50 | }; 51 | /* End PBXGroup section */ 52 | 53 | /* Begin PBXNativeTarget section */ 54 | 84DE939C2B202F62006BDECB /* DailyLog */ = { 55 | isa = PBXNativeTarget; 56 | buildConfigurationList = 84DE93B12B202F63006BDECB /* Build configuration list for PBXNativeTarget "DailyLog" */; 57 | buildPhases = ( 58 | 84DE93992B202F62006BDECB /* Sources */, 59 | 84DE939A2B202F62006BDECB /* Frameworks */, 60 | 84DE939B2B202F62006BDECB /* Resources */, 61 | ); 62 | buildRules = ( 63 | ); 64 | dependencies = ( 65 | ); 66 | fileSystemSynchronizedGroups = ( 67 | 84565F372CE791B90074DFDA /* App */, 68 | ); 69 | name = DailyLog; 70 | packageProductDependencies = ( 71 | 84565F482CE7921C0074DFDA /* HotwireNative */, 72 | ); 73 | productName = DailyLog; 74 | productReference = 848871002CE7CFEC00651A1C /* Daily Log.app */; 75 | productType = "com.apple.product-type.application"; 76 | }; 77 | /* End PBXNativeTarget section */ 78 | 79 | /* Begin PBXProject section */ 80 | 84DE93952B202F62006BDECB /* Project object */ = { 81 | isa = PBXProject; 82 | attributes = { 83 | BuildIndependentTargetsInParallel = 1; 84 | LastSwiftUpdateCheck = 1500; 85 | LastUpgradeCheck = 1500; 86 | TargetAttributes = { 87 | 84DE939C2B202F62006BDECB = { 88 | CreatedOnToolsVersion = 15.0.1; 89 | }; 90 | }; 91 | }; 92 | buildConfigurationList = 84DE93982B202F62006BDECB /* Build configuration list for PBXProject "DailyLog" */; 93 | compatibilityVersion = "Xcode 14.0"; 94 | developmentRegion = en; 95 | hasScannedForEncodings = 0; 96 | knownRegions = ( 97 | en, 98 | Base, 99 | ); 100 | mainGroup = 84DE93942B202F62006BDECB; 101 | packageReferences = ( 102 | 84565F472CE7921C0074DFDA /* XCRemoteSwiftPackageReference "hotwire-native-ios" */, 103 | ); 104 | productRefGroup = 84DE93942B202F62006BDECB; 105 | projectDirPath = ""; 106 | projectRoot = ""; 107 | targets = ( 108 | 84DE939C2B202F62006BDECB /* DailyLog */, 109 | ); 110 | }; 111 | /* End PBXProject section */ 112 | 113 | /* Begin PBXResourcesBuildPhase section */ 114 | 84DE939B2B202F62006BDECB /* Resources */ = { 115 | isa = PBXResourcesBuildPhase; 116 | buildActionMask = 2147483647; 117 | files = ( 118 | ); 119 | runOnlyForDeploymentPostprocessing = 0; 120 | }; 121 | /* End PBXResourcesBuildPhase section */ 122 | 123 | /* Begin PBXSourcesBuildPhase section */ 124 | 84DE93992B202F62006BDECB /* Sources */ = { 125 | isa = PBXSourcesBuildPhase; 126 | buildActionMask = 2147483647; 127 | files = ( 128 | ); 129 | runOnlyForDeploymentPostprocessing = 0; 130 | }; 131 | /* End PBXSourcesBuildPhase section */ 132 | 133 | /* Begin XCBuildConfiguration section */ 134 | 84DE93AF2B202F63006BDECB /* Debug */ = { 135 | isa = XCBuildConfiguration; 136 | buildSettings = { 137 | ALWAYS_SEARCH_USER_PATHS = NO; 138 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 139 | CLANG_ANALYZER_NONNULL = YES; 140 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 141 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 142 | CLANG_ENABLE_MODULES = YES; 143 | CLANG_ENABLE_OBJC_ARC = YES; 144 | CLANG_ENABLE_OBJC_WEAK = YES; 145 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 146 | CLANG_WARN_BOOL_CONVERSION = YES; 147 | CLANG_WARN_COMMA = YES; 148 | CLANG_WARN_CONSTANT_CONVERSION = YES; 149 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 150 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 151 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 152 | CLANG_WARN_EMPTY_BODY = YES; 153 | CLANG_WARN_ENUM_CONVERSION = YES; 154 | CLANG_WARN_INFINITE_RECURSION = YES; 155 | CLANG_WARN_INT_CONVERSION = YES; 156 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 157 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 158 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 159 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 160 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 161 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 162 | CLANG_WARN_STRICT_PROTOTYPES = YES; 163 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 164 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 165 | CLANG_WARN_UNREACHABLE_CODE = YES; 166 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 167 | COPY_PHASE_STRIP = NO; 168 | DEBUG_INFORMATION_FORMAT = dwarf; 169 | ENABLE_STRICT_OBJC_MSGSEND = YES; 170 | ENABLE_TESTABILITY = YES; 171 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 172 | GCC_C_LANGUAGE_STANDARD = gnu17; 173 | GCC_DYNAMIC_NO_PIC = NO; 174 | GCC_NO_COMMON_BLOCKS = YES; 175 | GCC_OPTIMIZATION_LEVEL = 0; 176 | GCC_PREPROCESSOR_DEFINITIONS = ( 177 | "DEBUG=1", 178 | "$(inherited)", 179 | ); 180 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 181 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 182 | GCC_WARN_UNDECLARED_SELECTOR = YES; 183 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 184 | GCC_WARN_UNUSED_FUNCTION = YES; 185 | GCC_WARN_UNUSED_VARIABLE = YES; 186 | IPHONEOS_DEPLOYMENT_TARGET = 17.0; 187 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES; 188 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 189 | MTL_FAST_MATH = YES; 190 | ONLY_ACTIVE_ARCH = YES; 191 | SDKROOT = iphoneos; 192 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; 193 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 194 | }; 195 | name = Debug; 196 | }; 197 | 84DE93B02B202F63006BDECB /* Release */ = { 198 | isa = XCBuildConfiguration; 199 | buildSettings = { 200 | ALWAYS_SEARCH_USER_PATHS = NO; 201 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 202 | CLANG_ANALYZER_NONNULL = YES; 203 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 204 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 205 | CLANG_ENABLE_MODULES = YES; 206 | CLANG_ENABLE_OBJC_ARC = YES; 207 | CLANG_ENABLE_OBJC_WEAK = YES; 208 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 209 | CLANG_WARN_BOOL_CONVERSION = YES; 210 | CLANG_WARN_COMMA = YES; 211 | CLANG_WARN_CONSTANT_CONVERSION = YES; 212 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 213 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 214 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 215 | CLANG_WARN_EMPTY_BODY = YES; 216 | CLANG_WARN_ENUM_CONVERSION = YES; 217 | CLANG_WARN_INFINITE_RECURSION = YES; 218 | CLANG_WARN_INT_CONVERSION = YES; 219 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 220 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 221 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 222 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 223 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 224 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 225 | CLANG_WARN_STRICT_PROTOTYPES = YES; 226 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 227 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 228 | CLANG_WARN_UNREACHABLE_CODE = YES; 229 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 230 | COPY_PHASE_STRIP = NO; 231 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 232 | ENABLE_NS_ASSERTIONS = NO; 233 | ENABLE_STRICT_OBJC_MSGSEND = YES; 234 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 235 | GCC_C_LANGUAGE_STANDARD = gnu17; 236 | GCC_NO_COMMON_BLOCKS = YES; 237 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 238 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 239 | GCC_WARN_UNDECLARED_SELECTOR = YES; 240 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 241 | GCC_WARN_UNUSED_FUNCTION = YES; 242 | GCC_WARN_UNUSED_VARIABLE = YES; 243 | IPHONEOS_DEPLOYMENT_TARGET = 17.0; 244 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES; 245 | MTL_ENABLE_DEBUG_INFO = NO; 246 | MTL_FAST_MATH = YES; 247 | SDKROOT = iphoneos; 248 | SWIFT_COMPILATION_MODE = wholemodule; 249 | VALIDATE_PRODUCT = YES; 250 | }; 251 | name = Release; 252 | }; 253 | 84DE93B22B202F63006BDECB /* Debug */ = { 254 | isa = XCBuildConfiguration; 255 | buildSettings = { 256 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 257 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 258 | CODE_SIGN_STYLE = Automatic; 259 | CURRENT_PROJECT_VERSION = 1; 260 | DEVELOPMENT_TEAM = 6JS2VP4ATY; 261 | GENERATE_INFOPLIST_FILE = YES; 262 | INFOPLIST_FILE = App/Resources/Info.plist; 263 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 264 | INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; 265 | INFOPLIST_KEY_UIMainStoryboardFile = Main; 266 | INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; 267 | LD_RUNPATH_SEARCH_PATHS = ( 268 | "$(inherited)", 269 | "@executable_path/Frameworks", 270 | ); 271 | MARKETING_VERSION = 1.2; 272 | PRODUCT_BUNDLE_IDENTIFIER = "com.masilotti.daily-log"; 273 | PRODUCT_NAME = "Daily Log"; 274 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; 275 | SUPPORTS_MACCATALYST = NO; 276 | SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; 277 | SWIFT_EMIT_LOC_STRINGS = YES; 278 | SWIFT_VERSION = 5.0; 279 | TARGETED_DEVICE_FAMILY = 1; 280 | }; 281 | name = Debug; 282 | }; 283 | 84DE93B32B202F63006BDECB /* Release */ = { 284 | isa = XCBuildConfiguration; 285 | buildSettings = { 286 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 287 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 288 | CODE_SIGN_STYLE = Automatic; 289 | CURRENT_PROJECT_VERSION = 1; 290 | DEVELOPMENT_TEAM = 6JS2VP4ATY; 291 | GENERATE_INFOPLIST_FILE = YES; 292 | INFOPLIST_FILE = App/Resources/Info.plist; 293 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 294 | INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; 295 | INFOPLIST_KEY_UIMainStoryboardFile = Main; 296 | INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; 297 | LD_RUNPATH_SEARCH_PATHS = ( 298 | "$(inherited)", 299 | "@executable_path/Frameworks", 300 | ); 301 | MARKETING_VERSION = 1.2; 302 | PRODUCT_BUNDLE_IDENTIFIER = "com.masilotti.daily-log"; 303 | PRODUCT_NAME = "Daily Log"; 304 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; 305 | SUPPORTS_MACCATALYST = NO; 306 | SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; 307 | SWIFT_EMIT_LOC_STRINGS = YES; 308 | SWIFT_VERSION = 5.0; 309 | TARGETED_DEVICE_FAMILY = 1; 310 | }; 311 | name = Release; 312 | }; 313 | /* End XCBuildConfiguration section */ 314 | 315 | /* Begin XCConfigurationList section */ 316 | 84DE93982B202F62006BDECB /* Build configuration list for PBXProject "DailyLog" */ = { 317 | isa = XCConfigurationList; 318 | buildConfigurations = ( 319 | 84DE93AF2B202F63006BDECB /* Debug */, 320 | 84DE93B02B202F63006BDECB /* Release */, 321 | ); 322 | defaultConfigurationIsVisible = 0; 323 | defaultConfigurationName = Release; 324 | }; 325 | 84DE93B12B202F63006BDECB /* Build configuration list for PBXNativeTarget "DailyLog" */ = { 326 | isa = XCConfigurationList; 327 | buildConfigurations = ( 328 | 84DE93B22B202F63006BDECB /* Debug */, 329 | 84DE93B32B202F63006BDECB /* Release */, 330 | ); 331 | defaultConfigurationIsVisible = 0; 332 | defaultConfigurationName = Release; 333 | }; 334 | /* End XCConfigurationList section */ 335 | 336 | /* Begin XCRemoteSwiftPackageReference section */ 337 | 84565F472CE7921C0074DFDA /* XCRemoteSwiftPackageReference "hotwire-native-ios" */ = { 338 | isa = XCRemoteSwiftPackageReference; 339 | repositoryURL = "https://github.com/hotwired/hotwire-native-ios"; 340 | requirement = { 341 | kind = upToNextMajorVersion; 342 | minimumVersion = 1.0.0; 343 | }; 344 | }; 345 | /* End XCRemoteSwiftPackageReference section */ 346 | 347 | /* Begin XCSwiftPackageProductDependency section */ 348 | 84565F482CE7921C0074DFDA /* HotwireNative */ = { 349 | isa = XCSwiftPackageProductDependency; 350 | package = 84565F472CE7921C0074DFDA /* XCRemoteSwiftPackageReference "hotwire-native-ios" */; 351 | productName = HotwireNative; 352 | }; 353 | /* End XCSwiftPackageProductDependency section */ 354 | }; 355 | rootObject = 84DE93952B202F62006BDECB /* Project object */; 356 | } 357 | -------------------------------------------------------------------------------- /ios/DailyLog.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/DailyLog.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/DailyLog.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "originHash" : "e043e35d89fc9c175f4169f4aa9709becdfb87b915ef76ee944456cb593c96b1", 3 | "pins" : [ 4 | { 5 | "identity" : "hotwire-native-ios", 6 | "kind" : "remoteSourceControl", 7 | "location" : "https://github.com/hotwired/hotwire-native-ios", 8 | "state" : { 9 | "revision" : "9c7d6c263a528c0a02e3796a5f451eb8405e2107", 10 | "version" : "1.0.0" 11 | } 12 | } 13 | ], 14 | "version" : 3 15 | } 16 | -------------------------------------------------------------------------------- /ios/README.md: -------------------------------------------------------------------------------- 1 | # Daily Log iOS app 2 | 3 | ## Quick start 4 | 5 | 1. `open DailyLog.xcodeproj` 6 | 1. Click Product → Run 7 | 8 | ## Requirements 9 | 10 | * Xcode 15.0 11 | 12 | ## Notes 13 | 14 | This app is currently pointing to unreleased branches for Turbo and Strada. When these PRs are merged the app will point back to official releases. 15 | 16 | * Turbo is pointing to [turbo-navigator](https://github.com/hotwired/turbo-ios/pull/158) which upstreams [Turbo Navigator](https://github.com/joemasilotti/TurboNavigator). 17 | * Strada is pointing to [fix-redirect-issue](https://github.com/hotwired/strada-ios/pull/24) which fixes an issue where Strada might "disconnect" if a page is redirected on app launch. 18 | -------------------------------------------------------------------------------- /rails/.dockerignore: -------------------------------------------------------------------------------- 1 | # See https://docs.docker.com/engine/reference/builder/#dockerignore-file for more about ignoring files. 2 | 3 | # Ignore git directory. 4 | /.git/ 5 | 6 | # Ignore bundler config. 7 | /.bundle 8 | 9 | # Ignore all default key files. 10 | /config/master.key 11 | /config/credentials/*.key 12 | 13 | # Ignore all environment files. 14 | /.env* 15 | !/.env.example 16 | 17 | # Ignore all logfiles and tempfiles. 18 | /log/* 19 | /tmp/* 20 | !/log/.keep 21 | !/tmp/.keep 22 | 23 | # Ignore pidfiles, but keep the directory. 24 | /tmp/pids/* 25 | !/tmp/pids/.keep 26 | 27 | # Ignore storage (uploaded files in development and any SQLite databases). 28 | /storage/* 29 | !/storage/.keep 30 | /tmp/storage/* 31 | !/tmp/storage/.keep 32 | 33 | # Ignore assets. 34 | /node_modules/ 35 | /app/assets/builds/* 36 | !/app/assets/builds/.keep 37 | /public/assets 38 | -------------------------------------------------------------------------------- /rails/.gitattributes: -------------------------------------------------------------------------------- 1 | # See https://git-scm.com/docs/gitattributes for more about git attribute files. 2 | 3 | # Mark the database schema as having been generated. 4 | db/schema.rb linguist-generated 5 | 6 | # Mark any vendored files as having been vendored. 7 | vendor/* linguist-vendored 8 | config/credentials/*.yml.enc diff=rails_credentials 9 | config/credentials.yml.enc diff=rails_credentials 10 | -------------------------------------------------------------------------------- /rails/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore bundler config. 2 | /.bundle 3 | 4 | # Ignore all environment files (except templates). 5 | /.env* 6 | !/.env*.erb 7 | 8 | # Ignore all logfiles and tempfiles. 9 | /log/* 10 | /tmp/* 11 | !/log/.keep 12 | !/tmp/.keep 13 | 14 | # Ignore pidfiles, but keep the directory. 15 | /tmp/pids/* 16 | !/tmp/pids/ 17 | !/tmp/pids/.keep 18 | 19 | # Ignore storage (uploaded files in development and any SQLite databases). 20 | /storage/* 21 | !/storage/.keep 22 | /tmp/storage/* 23 | !/tmp/storage/ 24 | !/tmp/storage/.keep 25 | 26 | # Ignore compiled assets, but keep the directory. 27 | /public/assets 28 | /app/assets/builds/* 29 | !/app/assets/builds/.keep 30 | 31 | # Ignore keys for decrypting credentials and more. 32 | /config/master.key 33 | /config/credentials/production.key 34 | -------------------------------------------------------------------------------- /rails/.ruby-version: -------------------------------------------------------------------------------- 1 | 3.2.2 2 | -------------------------------------------------------------------------------- /rails/Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax = docker/dockerfile:1 2 | 3 | # Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile 4 | ARG RUBY_VERSION=3.2.2 5 | FROM ruby:$RUBY_VERSION-slim as base 6 | 7 | # Rails app lives here 8 | WORKDIR /rails 9 | 10 | # Set production environment 11 | ENV RAILS_ENV="production" \ 12 | BUNDLE_WITHOUT="development:test" \ 13 | BUNDLE_DEPLOYMENT="1" 14 | 15 | # Update gems and bundler 16 | RUN gem update --system --no-document && \ 17 | gem install -N bundler 18 | 19 | 20 | # Throw-away build stage to reduce size of final image 21 | FROM base as build 22 | 23 | # Install packages needed to build gems 24 | RUN apt-get update -qq && \ 25 | apt-get install --no-install-recommends -y build-essential libpq-dev libvips 26 | 27 | # Install application gems 28 | COPY --link Gemfile Gemfile.lock ./ 29 | RUN bundle install && \ 30 | bundle exec bootsnap precompile --gemfile && \ 31 | rm -rf ~/.bundle/ $BUNDLE_PATH/ruby/*/cache $BUNDLE_PATH/ruby/*/bundler/gems/*/.git 32 | 33 | # Copy application code 34 | COPY --link . . 35 | 36 | # Precompile bootsnap code for faster boot times 37 | RUN bundle exec bootsnap precompile app/ lib/ 38 | 39 | # Precompiling assets for production without requiring secret RAILS_MASTER_KEY 40 | RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile 41 | 42 | 43 | # Final stage for app image 44 | FROM base 45 | 46 | # Install packages needed for deployment 47 | RUN apt-get update -qq && \ 48 | apt-get install --no-install-recommends -y curl imagemagick libvips postgresql-client && \ 49 | rm -rf /var/lib/apt/lists /var/cache/apt/archives 50 | 51 | # Copy built artifacts: gems, application 52 | COPY --from=build /usr/local/bundle /usr/local/bundle 53 | COPY --from=build /rails /rails 54 | 55 | # Run and own only the runtime files as a non-root user for security 56 | RUN useradd rails --create-home --shell /bin/bash && \ 57 | chown -R rails:rails db log storage tmp 58 | USER rails:rails 59 | 60 | # Entrypoint prepares the database. 61 | ENTRYPOINT ["/rails/bin/docker-entrypoint"] 62 | 63 | # Start the server by default, this can be overwritten at runtime 64 | EXPOSE 3000 65 | CMD ["./bin/rails", "server"] 66 | -------------------------------------------------------------------------------- /rails/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | ruby "3.2.2" 4 | 5 | gem "rails", "~> 7.1.2" 6 | 7 | gem "bcrypt", "~> 3.1.7" 8 | gem "bootsnap", require: false 9 | gem "honeybadger" 10 | gem "image_processing", "~> 1.2" 11 | gem "importmap-rails" 12 | gem "inline_svg" 13 | gem "jbuilder" 14 | gem "measured-rails" 15 | gem "pg", "~> 1.1" 16 | gem "puma", ">= 5.0" 17 | gem "redis", ">= 4.0.1" 18 | gem "sprockets-rails" 19 | gem "stimulus-rails" 20 | gem "tailwindcss-rails" 21 | gem "turbo-rails" 22 | gem "tzinfo-data", platforms: %i[windows jruby] 23 | 24 | group :development, :test do 25 | gem "pry-rails" 26 | gem "web-console" 27 | end 28 | 29 | group :development do 30 | gem "standard" 31 | end 32 | 33 | group :test do 34 | gem "capybara" 35 | gem "selenium-webdriver" 36 | end 37 | -------------------------------------------------------------------------------- /rails/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | actioncable (7.1.2) 5 | actionpack (= 7.1.2) 6 | activesupport (= 7.1.2) 7 | nio4r (~> 2.0) 8 | websocket-driver (>= 0.6.1) 9 | zeitwerk (~> 2.6) 10 | actionmailbox (7.1.2) 11 | actionpack (= 7.1.2) 12 | activejob (= 7.1.2) 13 | activerecord (= 7.1.2) 14 | activestorage (= 7.1.2) 15 | activesupport (= 7.1.2) 16 | mail (>= 2.7.1) 17 | net-imap 18 | net-pop 19 | net-smtp 20 | actionmailer (7.1.2) 21 | actionpack (= 7.1.2) 22 | actionview (= 7.1.2) 23 | activejob (= 7.1.2) 24 | activesupport (= 7.1.2) 25 | mail (~> 2.5, >= 2.5.4) 26 | net-imap 27 | net-pop 28 | net-smtp 29 | rails-dom-testing (~> 2.2) 30 | actionpack (7.1.2) 31 | actionview (= 7.1.2) 32 | activesupport (= 7.1.2) 33 | nokogiri (>= 1.8.5) 34 | racc 35 | rack (>= 2.2.4) 36 | rack-session (>= 1.0.1) 37 | rack-test (>= 0.6.3) 38 | rails-dom-testing (~> 2.2) 39 | rails-html-sanitizer (~> 1.6) 40 | actiontext (7.1.2) 41 | actionpack (= 7.1.2) 42 | activerecord (= 7.1.2) 43 | activestorage (= 7.1.2) 44 | activesupport (= 7.1.2) 45 | globalid (>= 0.6.0) 46 | nokogiri (>= 1.8.5) 47 | actionview (7.1.2) 48 | activesupport (= 7.1.2) 49 | builder (~> 3.1) 50 | erubi (~> 1.11) 51 | rails-dom-testing (~> 2.2) 52 | rails-html-sanitizer (~> 1.6) 53 | activejob (7.1.2) 54 | activesupport (= 7.1.2) 55 | globalid (>= 0.3.6) 56 | activemodel (7.1.2) 57 | activesupport (= 7.1.2) 58 | activerecord (7.1.2) 59 | activemodel (= 7.1.2) 60 | activesupport (= 7.1.2) 61 | timeout (>= 0.4.0) 62 | activestorage (7.1.2) 63 | actionpack (= 7.1.2) 64 | activejob (= 7.1.2) 65 | activerecord (= 7.1.2) 66 | activesupport (= 7.1.2) 67 | marcel (~> 1.0) 68 | activesupport (7.1.2) 69 | base64 70 | bigdecimal 71 | concurrent-ruby (~> 1.0, >= 1.0.2) 72 | connection_pool (>= 2.2.5) 73 | drb 74 | i18n (>= 1.6, < 2) 75 | minitest (>= 5.1) 76 | mutex_m 77 | tzinfo (~> 2.0) 78 | addressable (2.8.5) 79 | public_suffix (>= 2.0.2, < 6.0) 80 | ast (2.4.2) 81 | base64 (0.2.0) 82 | bcrypt (3.1.20) 83 | bigdecimal (3.1.4) 84 | bindex (0.8.1) 85 | bootsnap (1.17.0) 86 | msgpack (~> 1.2) 87 | builder (3.2.4) 88 | capybara (3.39.2) 89 | addressable 90 | matrix 91 | mini_mime (>= 0.1.3) 92 | nokogiri (~> 1.8) 93 | rack (>= 1.6.0) 94 | rack-test (>= 0.6.3) 95 | regexp_parser (>= 1.5, < 3.0) 96 | xpath (~> 3.2) 97 | coderay (1.1.3) 98 | concurrent-ruby (1.2.2) 99 | connection_pool (2.4.1) 100 | crass (1.0.6) 101 | date (3.3.4) 102 | drb (2.2.0) 103 | ruby2_keywords 104 | erubi (1.12.0) 105 | ffi (1.16.3) 106 | globalid (1.2.1) 107 | activesupport (>= 6.1) 108 | honeybadger (5.4.0) 109 | i18n (1.14.1) 110 | concurrent-ruby (~> 1.0) 111 | image_processing (1.12.2) 112 | mini_magick (>= 4.9.5, < 5) 113 | ruby-vips (>= 2.0.17, < 3) 114 | importmap-rails (1.2.3) 115 | actionpack (>= 6.0.0) 116 | activesupport (>= 6.0.0) 117 | railties (>= 6.0.0) 118 | inline_svg (1.9.0) 119 | activesupport (>= 3.0) 120 | nokogiri (>= 1.6) 121 | io-console (0.6.0) 122 | irb (1.10.0) 123 | rdoc 124 | reline (>= 0.3.8) 125 | jbuilder (2.11.5) 126 | actionview (>= 5.0.0) 127 | activesupport (>= 5.0.0) 128 | json (2.7.0) 129 | language_server-protocol (3.17.0.3) 130 | lint_roller (1.1.0) 131 | loofah (2.22.0) 132 | crass (~> 1.0.2) 133 | nokogiri (>= 1.12.0) 134 | mail (2.8.1) 135 | mini_mime (>= 0.1.1) 136 | net-imap 137 | net-pop 138 | net-smtp 139 | marcel (1.0.2) 140 | matrix (0.4.2) 141 | measured (2.8.2) 142 | activesupport (>= 5.2) 143 | measured-rails (2.8.2) 144 | activemodel (>= 5.2) 145 | activerecord (>= 5.2) 146 | measured (= 2.8.2) 147 | railties (>= 5.2) 148 | method_source (1.0.0) 149 | mini_magick (4.12.0) 150 | mini_mime (1.1.5) 151 | minitest (5.20.0) 152 | msgpack (1.7.2) 153 | mutex_m (0.2.0) 154 | net-imap (0.4.7) 155 | date 156 | net-protocol 157 | net-pop (0.1.2) 158 | net-protocol 159 | net-protocol (0.2.2) 160 | timeout 161 | net-smtp (0.4.0) 162 | net-protocol 163 | nio4r (2.7.0) 164 | nokogiri (1.15.5-aarch64-linux) 165 | racc (~> 1.4) 166 | nokogiri (1.15.5-arm64-darwin) 167 | racc (~> 1.4) 168 | nokogiri (1.15.5-x86_64-linux) 169 | racc (~> 1.4) 170 | parallel (1.23.0) 171 | parser (3.2.2.4) 172 | ast (~> 2.4.1) 173 | racc 174 | pg (1.5.4) 175 | pry (0.14.2) 176 | coderay (~> 1.1) 177 | method_source (~> 1.0) 178 | pry-rails (0.3.9) 179 | pry (>= 0.10.4) 180 | psych (5.1.1.1) 181 | stringio 182 | public_suffix (5.0.4) 183 | puma (6.4.0) 184 | nio4r (~> 2.0) 185 | racc (1.7.3) 186 | rack (3.0.8) 187 | rack-session (2.0.0) 188 | rack (>= 3.0.0) 189 | rack-test (2.1.0) 190 | rack (>= 1.3) 191 | rackup (2.1.0) 192 | rack (>= 3) 193 | webrick (~> 1.8) 194 | rails (7.1.2) 195 | actioncable (= 7.1.2) 196 | actionmailbox (= 7.1.2) 197 | actionmailer (= 7.1.2) 198 | actionpack (= 7.1.2) 199 | actiontext (= 7.1.2) 200 | actionview (= 7.1.2) 201 | activejob (= 7.1.2) 202 | activemodel (= 7.1.2) 203 | activerecord (= 7.1.2) 204 | activestorage (= 7.1.2) 205 | activesupport (= 7.1.2) 206 | bundler (>= 1.15.0) 207 | railties (= 7.1.2) 208 | rails-dom-testing (2.2.0) 209 | activesupport (>= 5.0.0) 210 | minitest 211 | nokogiri (>= 1.6) 212 | rails-html-sanitizer (1.6.0) 213 | loofah (~> 2.21) 214 | nokogiri (~> 1.14) 215 | railties (7.1.2) 216 | actionpack (= 7.1.2) 217 | activesupport (= 7.1.2) 218 | irb 219 | rackup (>= 1.0.0) 220 | rake (>= 12.2) 221 | thor (~> 1.0, >= 1.2.2) 222 | zeitwerk (~> 2.6) 223 | rainbow (3.1.1) 224 | rake (13.1.0) 225 | rdoc (6.6.0) 226 | psych (>= 4.0.0) 227 | redis (5.0.8) 228 | redis-client (>= 0.17.0) 229 | redis-client (0.18.0) 230 | connection_pool 231 | regexp_parser (2.8.3) 232 | reline (0.4.1) 233 | io-console (~> 0.5) 234 | rexml (3.2.6) 235 | rubocop (1.57.2) 236 | json (~> 2.3) 237 | language_server-protocol (>= 3.17.0) 238 | parallel (~> 1.10) 239 | parser (>= 3.2.2.4) 240 | rainbow (>= 2.2.2, < 4.0) 241 | regexp_parser (>= 1.8, < 3.0) 242 | rexml (>= 3.2.5, < 4.0) 243 | rubocop-ast (>= 1.28.1, < 2.0) 244 | ruby-progressbar (~> 1.7) 245 | unicode-display_width (>= 2.4.0, < 3.0) 246 | rubocop-ast (1.30.0) 247 | parser (>= 3.2.1.0) 248 | rubocop-performance (1.19.1) 249 | rubocop (>= 1.7.0, < 2.0) 250 | rubocop-ast (>= 0.4.0) 251 | ruby-progressbar (1.13.0) 252 | ruby-vips (2.2.0) 253 | ffi (~> 1.12) 254 | ruby2_keywords (0.0.5) 255 | rubyzip (2.3.2) 256 | selenium-webdriver (4.15.0) 257 | rexml (~> 3.2, >= 3.2.5) 258 | rubyzip (>= 1.2.2, < 3.0) 259 | websocket (~> 1.0) 260 | sprockets (4.2.1) 261 | concurrent-ruby (~> 1.0) 262 | rack (>= 2.2.4, < 4) 263 | sprockets-rails (3.4.2) 264 | actionpack (>= 5.2) 265 | activesupport (>= 5.2) 266 | sprockets (>= 3.0.0) 267 | standard (1.32.1) 268 | language_server-protocol (~> 3.17.0.2) 269 | lint_roller (~> 1.0) 270 | rubocop (~> 1.57.2) 271 | standard-custom (~> 1.0.0) 272 | standard-performance (~> 1.2) 273 | standard-custom (1.0.2) 274 | lint_roller (~> 1.0) 275 | rubocop (~> 1.50) 276 | standard-performance (1.2.1) 277 | lint_roller (~> 1.1) 278 | rubocop-performance (~> 1.19.1) 279 | stimulus-rails (1.3.0) 280 | railties (>= 6.0.0) 281 | stringio (3.1.0) 282 | tailwindcss-rails (2.0.32-aarch64-linux) 283 | railties (>= 6.0.0) 284 | tailwindcss-rails (2.0.32-arm64-darwin) 285 | railties (>= 6.0.0) 286 | tailwindcss-rails (2.0.32-x86_64-linux) 287 | railties (>= 6.0.0) 288 | thor (1.3.0) 289 | timeout (0.4.1) 290 | turbo-rails (1.5.0) 291 | actionpack (>= 6.0.0) 292 | activejob (>= 6.0.0) 293 | railties (>= 6.0.0) 294 | tzinfo (2.0.6) 295 | concurrent-ruby (~> 1.0) 296 | unicode-display_width (2.5.0) 297 | web-console (4.2.1) 298 | actionview (>= 6.0.0) 299 | activemodel (>= 6.0.0) 300 | bindex (>= 0.4.0) 301 | railties (>= 6.0.0) 302 | webrick (1.8.1) 303 | websocket (1.2.10) 304 | websocket-driver (0.7.6) 305 | websocket-extensions (>= 0.1.0) 306 | websocket-extensions (0.1.5) 307 | xpath (3.2.0) 308 | nokogiri (~> 1.8) 309 | zeitwerk (2.6.12) 310 | 311 | PLATFORMS 312 | aarch64-linux 313 | arm64-darwin-22 314 | x86_64-linux 315 | 316 | DEPENDENCIES 317 | bcrypt (~> 3.1.7) 318 | bootsnap 319 | capybara 320 | honeybadger 321 | image_processing (~> 1.2) 322 | importmap-rails 323 | inline_svg 324 | jbuilder 325 | measured-rails 326 | pg (~> 1.1) 327 | pry-rails 328 | puma (>= 5.0) 329 | rails (~> 7.1.2) 330 | redis (>= 4.0.1) 331 | selenium-webdriver 332 | sprockets-rails 333 | standard 334 | stimulus-rails 335 | tailwindcss-rails 336 | turbo-rails 337 | tzinfo-data 338 | web-console 339 | 340 | RUBY VERSION 341 | ruby 3.2.2p53 342 | 343 | BUNDLED WITH 344 | 2.4.21 345 | -------------------------------------------------------------------------------- /rails/Procfile: -------------------------------------------------------------------------------- 1 | web: bundle exec puma -C config/puma.rb 2 | release: bin/rails db:migrate 3 | -------------------------------------------------------------------------------- /rails/Procfile.dev: -------------------------------------------------------------------------------- 1 | web: env RUBY_DEBUG_OPEN=true bin/rails server -p 3000 2 | css: bin/rails tailwindcss:watch 3 | -------------------------------------------------------------------------------- /rails/README.md: -------------------------------------------------------------------------------- 1 | # Daily Log Rails app 2 | 3 | ## Quick start 4 | 5 | 1. `bin/setup` 6 | 1. `bin/rails server` 7 | 8 | ## Requirements 9 | 10 | * Ruby 3.2.2 11 | * PostgreSQL 9.3 - `brew install pg` 12 | 13 | ## Initial setup 14 | 15 | An installation script is included with the repository that will get the application set up. 16 | 17 | ```bash 18 | bin/setup 19 | ``` 20 | 21 | ## Development 22 | 23 | Start the server. 24 | 25 | ```bash 26 | bin/dev 27 | ``` 28 | 29 | ## Database seeds 30 | 31 | Seeding the database, either via `rails db:seed` or during `bin/setup`, creates a demo account. 32 | 33 | * Email: `user@example.com` 34 | * Password: `password` 35 | -------------------------------------------------------------------------------- /rails/Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require_relative "config/application" 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /rails/app/assets/builds/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joemasilotti/daily-log/2458b5bd901b656fe9e9874c9cdb815c5b0a930c/rails/app/assets/builds/.keep -------------------------------------------------------------------------------- /rails/app/assets/config/manifest.js: -------------------------------------------------------------------------------- 1 | //= link_tree ../images 2 | //= link_directory ../stylesheets .css 3 | //= link_tree ../../javascript .js 4 | //= link_tree ../../../vendor/javascript .js 5 | //= link_tree ../builds 6 | -------------------------------------------------------------------------------- /rails/app/assets/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joemasilotti/daily-log/2458b5bd901b656fe9e9874c9cdb815c5b0a930c/rails/app/assets/images/.keep -------------------------------------------------------------------------------- /rails/app/assets/images/app_store.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joemasilotti/daily-log/2458b5bd901b656fe9e9874c9cdb815c5b0a930c/rails/app/assets/images/app_store.png -------------------------------------------------------------------------------- /rails/app/assets/images/github.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /rails/app/assets/images/icons/mini/check_circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /rails/app/assets/images/icons/mini/chevron_left.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /rails/app/assets/images/icons/mini/chevron_right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /rails/app/assets/images/icons/mini/plus.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /rails/app/assets/images/icons/mini/x_circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /rails/app/assets/images/icons/outline/user_circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /rails/app/assets/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /rails/app/assets/images/screenshots/ios.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joemasilotti/daily-log/2458b5bd901b656fe9e9874c9cdb815c5b0a930c/rails/app/assets/images/screenshots/ios.png -------------------------------------------------------------------------------- /rails/app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS (and SCSS, if configured) file within this directory, lib/assets/stylesheets, or any plugin's 6 | * vendor/assets/stylesheets directory can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the 9 | * compiled file so the styles you add here take precedence over styles defined in any other CSS 10 | * files in this directory. Styles in this file should be added after the last require_* statement. 11 | * It is generally better to create a new file per style scope. 12 | * 13 | *= require_tree . 14 | *= require_self 15 | */ 16 | -------------------------------------------------------------------------------- /rails/app/assets/stylesheets/application.tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer components { 6 | .btn-primary { 7 | @apply rounded-md bg-primary-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-primary-500 cursor-pointer focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-600; 8 | } 9 | 10 | .btn-secondary { 11 | @apply rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50; 12 | } 13 | 14 | .form-container { 15 | @apply border-b border-gray-900/10 pb-8 sm:pb-12 turbo-native:border-0 turbo-native:pb-0; 16 | } 17 | 18 | .form-group { 19 | @apply mt-6 sm:mt-10; 20 | } 21 | 22 | .form-checkbox-group { 23 | @apply relative flex items-center; 24 | } 25 | 26 | .form-label { 27 | @apply block text-sm font-medium leading-6 text-gray-900; 28 | } 29 | 30 | .form-text { 31 | @apply text-sm leading-6 text-gray-600; 32 | } 33 | 34 | .form-input { 35 | @apply block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-primary-600 sm:text-sm sm:leading-6 mt-2; 36 | } 37 | 38 | .form-checkbox { 39 | @apply h-4 w-4 rounded border-gray-300 text-primary-600 focus:ring-primary-600 mr-3; 40 | } 41 | 42 | .form-select { 43 | @apply mt-2 block w-full rounded-md border-0 py-1.5 pl-3 pr-10 text-gray-900 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-primary-600 sm:text-sm sm:leading-6; 44 | } 45 | 46 | .form-radio { 47 | @apply h-4 w-4 border-gray-300 text-primary-600 focus:ring-primary-600; 48 | } 49 | 50 | .form-buttons { 51 | @apply mt-6 flex items-center justify-end gap-x-6; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /rails/app/assets/stylesheets/strada.css: -------------------------------------------------------------------------------- 1 | /* bridge--form component */ 2 | [data-bridge-components~="form"] 3 | [data-controller~="bridge--form"] 4 | [type="submit"] { 5 | display: none; 6 | } 7 | 8 | /* bridge--button component */ 9 | [data-bridge-components~="button"] 10 | [data-controller~="bridge--button"] { 11 | display: none; 12 | } 13 | -------------------------------------------------------------------------------- /rails/app/channels/application_cable/channel.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Channel < ActionCable::Channel::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /rails/app/channels/application_cable/connection.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Connection < ActionCable::Connection::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /rails/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | include Authentication 3 | include HoneybadgerContext 4 | 5 | before_action :authenticate_user! 6 | before_action :set_honeybadger_context 7 | 8 | around_action :set_time_zone, if: :user_signed_in? 9 | 10 | def set_time_zone(&block) 11 | Time.use_zone(current_user.settings.time_zone, &block) 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /rails/app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joemasilotti/daily-log/2458b5bd901b656fe9e9874c9cdb815c5b0a930c/rails/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /rails/app/controllers/concerns/authentication.rb: -------------------------------------------------------------------------------- 1 | module Authentication 2 | extend ActiveSupport::Concern 3 | 4 | included do 5 | helper_method :current_user, :user_signed_in? 6 | end 7 | 8 | def sign_in(user) 9 | Current.user = user 10 | cookies.encrypted.permanent[:user_id] = user.id 11 | end 12 | 13 | def sign_out(user) 14 | Current.user = nil 15 | reset_session 16 | cookies.delete(:user_id) 17 | end 18 | 19 | def authenticate_user! 20 | if current_user.blank? 21 | redirect_to new_session_path, alert: "You need to sign in to continue." 22 | end 23 | end 24 | 25 | def redirect_if_authenticated 26 | redirect_to days_path if user_signed_in? 27 | end 28 | 29 | private 30 | 31 | def current_user 32 | Current.user ||= authenticate_user_from_session 33 | end 34 | 35 | def user_signed_in? 36 | current_user.present? 37 | end 38 | 39 | def authenticate_user_from_session 40 | User.find_by(id: cookies.encrypted[:user_id]) 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /rails/app/controllers/concerns/has_date.rb: -------------------------------------------------------------------------------- 1 | module HasDate 2 | extend ActiveSupport::Concern 3 | 4 | included do 5 | before_action :set_date 6 | end 7 | 8 | def set_date 9 | @date = Date.parse(params[:date].to_s) 10 | rescue Date::Error 11 | @date = Date.current 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /rails/app/controllers/concerns/honeybadger_context.rb: -------------------------------------------------------------------------------- 1 | module HoneybadgerContext 2 | extend ActiveSupport::Concern 3 | 4 | def set_honeybadger_context 5 | Honeybadger.context(current_user) 6 | end 7 | 8 | def clear_honeybadger_context 9 | Honeybadger.context.clear! 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /rails/app/controllers/configurations_controller.rb: -------------------------------------------------------------------------------- 1 | class ConfigurationsController < ApplicationController 2 | skip_before_action :authenticate_user! 3 | 4 | def ios 5 | render json: { 6 | settings: {}, 7 | rules: [ 8 | { 9 | patterns: ["/recede_historical_location"], 10 | properties: { 11 | presentation: "pop" 12 | } 13 | }, 14 | { 15 | patterns: [ 16 | "/new$", 17 | "/edit$", 18 | "/settings" 19 | ], 20 | properties: { 21 | context: "modal" 22 | } 23 | } 24 | ] 25 | } 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /rails/app/controllers/days_controller.rb: -------------------------------------------------------------------------------- 1 | class DaysController < ApplicationController 2 | before_action :set_date 3 | 4 | def index 5 | redirect_to day_path(Date.current) 6 | end 7 | 8 | def show 9 | @exercise_entries = current_user.exercise_entries.where(occurred_on: @date).order(:created_at) 10 | @medication_entries = current_user.medication_entries.where(occurred_on: @date).order(:created_at) 11 | @water = current_user.water_entries.where(occurred_on: @date).amounts.sum.convert_to(current_user.settings.water_unit) 12 | @food_entries = current_user.food_entries.where(occurred_on: @date).order(:created_at) 13 | end 14 | 15 | private 16 | 17 | def set_date 18 | @date = Date.parse(params[:id].to_s) 19 | rescue Date::Error 20 | redirect_to day_path(Date.current) 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /rails/app/controllers/exercise_entries_controller.rb: -------------------------------------------------------------------------------- 1 | class ExerciseEntriesController < ApplicationController 2 | include HasDate 3 | 4 | def new 5 | @entry = ExerciseEntry.new 6 | end 7 | 8 | def create 9 | @entry = ExerciseEntry.new(entry_params) 10 | if @entry.save 11 | redirect_to day_path(@entry.occurred_on), notice: "Added #{@entry.name}" 12 | else 13 | render :new, status: :unprocessable_entity 14 | end 15 | end 16 | 17 | def edit 18 | @entry = current_user.exercise_entries.find(params[:id]) 19 | end 20 | 21 | def update 22 | @entry = current_user.exercise_entries.find(params[:id]) 23 | if @entry.update(entry_params) 24 | redirect_to day_path(@entry.occurred_on), notice: "Updated #{@entry.name}" 25 | else 26 | render :new, status: :unprocessable_entity 27 | end 28 | end 29 | 30 | private 31 | 32 | def entry_params 33 | params.require(:exercise_entry).permit(:name, :occurred_on) 34 | .merge(user: current_user) 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /rails/app/controllers/food_entries_controller.rb: -------------------------------------------------------------------------------- 1 | class FoodEntriesController < ApplicationController 2 | include HasDate 3 | 4 | def new 5 | @entry = FoodEntry.new 6 | end 7 | 8 | def create 9 | @entry = FoodEntry.new(entry_params) 10 | if @entry.save 11 | redirect_to day_path(@entry.occurred_on), notice: "Added #{@entry.name}" 12 | else 13 | render :new, status: :unprocessable_entity 14 | end 15 | end 16 | 17 | def edit 18 | @entry = current_user.food_entries.find(params[:id]) 19 | end 20 | 21 | def update 22 | @entry = current_user.food_entries.find(params[:id]) 23 | if @entry.update(entry_params) 24 | redirect_to day_path(@entry.occurred_on), notice: "Updated #{@entry.name}" 25 | else 26 | render :new, status: :unprocessable_entity 27 | end 28 | end 29 | 30 | private 31 | 32 | def entry_params 33 | params.require(:food_entry).permit(:name, :out, :occurred_on) 34 | .merge(user: current_user) 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /rails/app/controllers/home_controller.rb: -------------------------------------------------------------------------------- 1 | class HomeController < ApplicationController 2 | skip_before_action :authenticate_user! 3 | before_action :redirect_if_authenticated 4 | end 5 | -------------------------------------------------------------------------------- /rails/app/controllers/medication_entries_controller.rb: -------------------------------------------------------------------------------- 1 | class MedicationEntriesController < ApplicationController 2 | include HasDate 3 | 4 | def new 5 | @entry = MedicationEntry.new 6 | end 7 | 8 | def create 9 | @entry = MedicationEntry.new(entry_params) 10 | if @entry.save 11 | redirect_to day_path(@entry.occurred_on), notice: "Added #{@entry.name}" 12 | else 13 | render :new, status: :unprocessable_entity 14 | end 15 | end 16 | 17 | def edit 18 | @entry = current_user.medication_entries.find(params[:id]) 19 | end 20 | 21 | def update 22 | @entry = current_user.medication_entries.find(params[:id]) 23 | if @entry.update(entry_params) 24 | redirect_to day_path(@entry.occurred_on), notice: "Updated #{@entry.name}" 25 | else 26 | render :new, status: :unprocessable_entity 27 | end 28 | end 29 | 30 | private 31 | 32 | def entry_params 33 | params.require(:medication_entry).permit(:name, :occurred_on) 34 | .merge(user: current_user) 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /rails/app/controllers/sessions_controller.rb: -------------------------------------------------------------------------------- 1 | class SessionsController < ApplicationController 2 | skip_before_action :authenticate_user!, only: %i[new create] 3 | before_action :redirect_if_authenticated, only: :new 4 | 5 | def create 6 | if (user = User.authenticate_by(authentication_params)) 7 | sign_in user 8 | redirect_to days_path, notice: "You are now signed in." 9 | else 10 | flash.now.alert = "Invalid email or password." 11 | render :new, status: :unprocessable_entity 12 | end 13 | end 14 | 15 | def destroy 16 | sign_out current_user 17 | clear_honeybadger_context 18 | redirect_to root_path, notice: "You are no longer signed in." 19 | end 20 | 21 | private 22 | 23 | def authentication_params 24 | {email: params[:email], password: params[:password]} 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /rails/app/controllers/settings_controller.rb: -------------------------------------------------------------------------------- 1 | class SettingsController < ApplicationController 2 | def edit 3 | @settings = current_user.settings 4 | end 5 | 6 | def update 7 | @settings = current_user.settings 8 | if @settings.update(settings_params) 9 | redirect_after_update 10 | else 11 | render :edit, status: :unprocessable_entity 12 | end 13 | end 14 | 15 | private 16 | 17 | def settings_params 18 | params.require(:setting).permit(:measurement_system, :time_zone) 19 | end 20 | 21 | def redirect_after_update 22 | if turbo_native_app? 23 | redirect_to turbo_recede_historical_location_path 24 | else 25 | redirect_to settings_path, notice: "Settings updated" 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /rails/app/controllers/users_controller.rb: -------------------------------------------------------------------------------- 1 | class UsersController < ApplicationController 2 | skip_before_action :authenticate_user! 3 | before_action :redirect_if_authenticated, except: :destroy 4 | 5 | def new 6 | @user = User.new 7 | end 8 | 9 | def create 10 | @user = User.create(user_params) 11 | if @user.valid? 12 | sign_in @user 13 | redirect_to days_path, notice: "Welcome to Daily Log!" 14 | else 15 | render :new, status: :unprocessable_entity 16 | end 17 | end 18 | 19 | def destroy 20 | current_user.destroy! 21 | clear_honeybadger_context 22 | redirect_to root_path, notice: "Your account and all associated data have been deleted." 23 | end 24 | 25 | private 26 | 27 | def user_params 28 | params.require(:user).permit(:email, :password, :password_confirmation) 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /rails/app/controllers/water_entries_controller.rb: -------------------------------------------------------------------------------- 1 | class WaterEntriesController < ApplicationController 2 | include HasDate 3 | 4 | def new 5 | @entry = WaterEntry.new 6 | @recent_entries = current_user.water_entries.recent 7 | end 8 | 9 | def create 10 | @entry = WaterEntry.new(entry_params) 11 | if @entry.save 12 | redirect_to day_path(@entry.occurred_on), notice: "Added #{@entry.amount} of water" 13 | else 14 | @recent_entries = current_user.water_entries.recent 15 | render :new, status: :unprocessable_entity 16 | end 17 | end 18 | 19 | private 20 | 21 | def entry_params 22 | params.require(:water_entry).permit(:amount_value, :amount_unit, :occurred_on) 23 | .merge(user: current_user) 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /rails/app/helpers/analytics_helper.rb: -------------------------------------------------------------------------------- 1 | module AnalyticsHelper 2 | def analytics_tag 3 | if (site_id = Rails.configuration.fathom) 4 | javascript_include_tag "https://cdn.usefathom.com/script.js", 5 | defer: true, data: {site: site_id} 6 | end 7 | end 8 | 9 | def track_page_view_script 10 | if Rails.configuration.fathom.present? 11 | javascript_tag do 12 | <<-JS.strip_heredoc.html_safe 13 | document.addEventListener("turbo:load", () => { 14 | if (window.fathom) { 15 | window.fathom.trackPageview() 16 | } 17 | }) 18 | JS 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /rails/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /rails/app/helpers/date_helper.rb: -------------------------------------------------------------------------------- 1 | module DateHelper 2 | def prev_day_path(date) 3 | day_path(date - 1.day) 4 | end 5 | 6 | def next_day_path(date) 7 | day_path(date + 1.day) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /rails/app/helpers/form_helper.rb: -------------------------------------------------------------------------------- 1 | module FormHelper 2 | class StradaFormBuilder < ActionView::Helpers::FormBuilder 3 | def submit(value = nil, options = {}) 4 | options[:data] ||= {} 5 | options["data-bridge--form-target"] = "submit" 6 | 7 | super(value, options) 8 | end 9 | end 10 | 11 | def strada_form_with(*, **options, &block) 12 | options[:html] ||= {} 13 | options[:html][:data] ||= {} 14 | options[:html][:data] = options[:html][:data].merge(strada_form_data) 15 | 16 | options[:builder] = StradaFormBuilder 17 | 18 | form_with(*, **options, &block) 19 | end 20 | 21 | private 22 | 23 | def strada_form_data 24 | { 25 | controller: "bridge--form", 26 | action: "turbo:submit-start->bridge--form#submitStart turbo:submit-end->bridge--form#submitEnd" 27 | } 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /rails/app/helpers/turbo_native_helper.rb: -------------------------------------------------------------------------------- 1 | module TurboNativeHelper 2 | def page_title 3 | if turbo_native_app? 4 | content_for(:turbo_native_title) || content_for(:title) || "Daily Log" 5 | else 6 | content_for(:title) || "Daily Log" 7 | end 8 | end 9 | 10 | def platform_identifier 11 | "turbo-native" if turbo_native_app? 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /rails/app/javascript/application.js: -------------------------------------------------------------------------------- 1 | // Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails 2 | import "@hotwired/turbo-rails" 3 | import "controllers" 4 | -------------------------------------------------------------------------------- /rails/app/javascript/controllers/application.js: -------------------------------------------------------------------------------- 1 | import { Application } from "@hotwired/stimulus" 2 | 3 | const application = Application.start() 4 | 5 | // Configure Stimulus development experience 6 | application.debug = false 7 | window.Stimulus = application 8 | 9 | export { application } 10 | -------------------------------------------------------------------------------- /rails/app/javascript/controllers/bridge/button_controller.js: -------------------------------------------------------------------------------- 1 | import { BridgeComponent } from "@hotwired/strada" 2 | 3 | export default class extends BridgeComponent { 4 | static component = "button" 5 | 6 | connect() { 7 | super.connect() 8 | this.#notifyBridgeOfConnect() 9 | } 10 | 11 | #notifyBridgeOfConnect() { 12 | const element = this.bridgeElement 13 | const image = element.bridgeAttribute("ios-image") 14 | const side = element.bridgeAttribute("side") || "right" 15 | this.send("connect", {title: element.title, image, side}, () => { 16 | this.element.click() 17 | }) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /rails/app/javascript/controllers/bridge/form_controller.js: -------------------------------------------------------------------------------- 1 | import { BridgeComponent, BridgeElement } from "@hotwired/strada" 2 | 3 | export default class extends BridgeComponent { 4 | static component = "form" 5 | static targets = ["submit"] 6 | 7 | connect() { 8 | super.connect() 9 | this.#notifyBridgeOfConnect() 10 | } 11 | 12 | submitStart(event) { 13 | this.submitTarget.disabled = true 14 | this.send("submitDisabled") 15 | } 16 | 17 | submitEnd(event) { 18 | this.submitTarget.disabled = false 19 | this.send("submitEnabled") 20 | } 21 | 22 | #notifyBridgeOfConnect() { 23 | const submitButton = new BridgeElement(this.submitTarget) 24 | const submitTitle = submitButton.bridgeAttribute("title") || submitButton.title 25 | 26 | this.send("connect", {submitTitle}, () => { 27 | this.submitTarget.click() 28 | }) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /rails/app/javascript/controllers/bridge/navigation_controller.js: -------------------------------------------------------------------------------- 1 | import { BridgeComponent, BridgeElement } from "@hotwired/strada" 2 | 3 | export default class extends BridgeComponent { 4 | static component = "navigation" 5 | static targets = ["previous", "next"] 6 | 7 | connect() { 8 | super.connect() 9 | 10 | if (this.hasPreviousTarget) { 11 | this.send("previous", {}, () => { 12 | new BridgeElement(this.previousTarget).click() 13 | }) 14 | } 15 | 16 | if (this.hasNextTarget) { 17 | this.send("next", {}, () => { 18 | new BridgeElement(this.nextTarget).click() 19 | }) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /rails/app/javascript/controllers/index.js: -------------------------------------------------------------------------------- 1 | // Import and register all your controllers from the importmap under controllers/* 2 | 3 | import { application } from "controllers/application" 4 | 5 | // Lazy load controllers as they appear in the DOM (remember not to preload controllers in import map!) 6 | import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading" 7 | lazyLoadControllersFrom("controllers", application) 8 | -------------------------------------------------------------------------------- /rails/app/jobs/application_job.rb: -------------------------------------------------------------------------------- 1 | class ApplicationJob < ActiveJob::Base 2 | # Automatically retry jobs that encountered a deadlock 3 | retry_on ActiveRecord::Deadlocked 4 | 5 | # Most jobs are safe to ignore if the underlying records are no longer available 6 | discard_on ActiveJob::DeserializationError 7 | end 8 | -------------------------------------------------------------------------------- /rails/app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | class ApplicationMailer < ActionMailer::Base 2 | default from: "joe@masilotti.com" 3 | layout "mailer" 4 | end 5 | -------------------------------------------------------------------------------- /rails/app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | class ApplicationRecord < ActiveRecord::Base 2 | primary_abstract_class 3 | end 4 | -------------------------------------------------------------------------------- /rails/app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joemasilotti/daily-log/2458b5bd901b656fe9e9874c9cdb815c5b0a930c/rails/app/models/concerns/.keep -------------------------------------------------------------------------------- /rails/app/models/current.rb: -------------------------------------------------------------------------------- 1 | class Current < ActiveSupport::CurrentAttributes 2 | attribute :user 3 | end 4 | -------------------------------------------------------------------------------- /rails/app/models/exercise_entry.rb: -------------------------------------------------------------------------------- 1 | class ExerciseEntry < ApplicationRecord 2 | validates :name, :occurred_on, presence: true 3 | 4 | belongs_to :user 5 | 6 | encrypts :name 7 | end 8 | -------------------------------------------------------------------------------- /rails/app/models/food_entry.rb: -------------------------------------------------------------------------------- 1 | class FoodEntry < ApplicationRecord 2 | validates :name, :occurred_on, presence: true 3 | validates :out, inclusion: [true, false] 4 | 5 | belongs_to :user 6 | 7 | encrypts :name 8 | end 9 | -------------------------------------------------------------------------------- /rails/app/models/medication_entry.rb: -------------------------------------------------------------------------------- 1 | class MedicationEntry < ApplicationRecord 2 | validates :name, :occurred_on, presence: true 3 | 4 | belongs_to :user 5 | 6 | encrypts :name 7 | end 8 | -------------------------------------------------------------------------------- /rails/app/models/setting.rb: -------------------------------------------------------------------------------- 1 | class Setting < ApplicationRecord 2 | belongs_to :user 3 | 4 | validates :time_zone, time_zone: true 5 | 6 | enum measurement_system: { 7 | imperial: "imperial", 8 | metric: "metric" 9 | } 10 | 11 | def water_unit 12 | WaterEntry.units[measurement_system.to_sym] 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /rails/app/models/user.rb: -------------------------------------------------------------------------------- 1 | class User < ApplicationRecord 2 | has_secure_password 3 | 4 | validates :email, presence: true, uniqueness: true 5 | 6 | normalizes :email, with: -> { _1.strip.downcase } 7 | 8 | has_many :exercise_entries, dependent: :destroy 9 | has_many :medication_entries, dependent: :destroy 10 | has_many :water_entries, dependent: :destroy 11 | has_many :food_entries, dependent: :destroy 12 | 13 | has_one :settings, dependent: :destroy, class_name: "Setting" 14 | 15 | after_create_commit :create_settings! 16 | 17 | encrypts :email, deterministic: true, downcase: true 18 | 19 | def to_honeybadger_context 20 | { 21 | user_id: id, 22 | user_email: email 23 | } 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /rails/app/models/water_entry.rb: -------------------------------------------------------------------------------- 1 | class WaterEntry < ApplicationRecord 2 | validates :occurred_on, presence: true 3 | validates :amount, presence: true 4 | validates :amount, measured: {greater_than: 0} 5 | 6 | belongs_to :user 7 | 8 | scope :recent, -> { distinct(:amount).order(created_at: :desc).limit(3) } 9 | scope :amounts, -> { map(&:amount).presence || [Measured::Volume.new(0, :oz)] } 10 | 11 | measured_volume :amount 12 | 13 | def self.units 14 | { 15 | imperial: "oz", 16 | metric: "ml" 17 | } 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /rails/app/validators/time_zone_validator.rb: -------------------------------------------------------------------------------- 1 | class TimeZoneValidator < ActiveModel::EachValidator 2 | def validate_each(record, attribute, value) 3 | unless ActiveSupport::TimeZone[value].present? 4 | record.errors.add(attribute, (options[:message] || "is not a valid time zone")) 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /rails/app/views/days/_navigation.html.erb: -------------------------------------------------------------------------------- 1 | <%# locals: (date:) %> 2 | 3 | 4 | <%= link_to prev_day_path(date), "data-bridge--navigation-target": "previous", "data-turbo-action": "replace", class: "relative inline-flex items-center rounded-l-md bg-white p-1.5 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10" do %> 5 | Previous day 6 | <%= inline_svg "icons/mini/chevron_left.svg", class: "w-5 h-5" %> 7 | <% end %> 8 | <%= link_to next_day_path(date), "data-bridge--navigation-target": "next", "data-turbo-action": "replace", class: "relative -ml-px inline-flex items-center rounded-r-md bg-white p-1.5 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10" do %> 9 | Next day 10 | <%= inline_svg "icons/mini/chevron_right.svg", class: "w-5 h-5" %> 11 | <% end %> 12 | 13 | -------------------------------------------------------------------------------- /rails/app/views/days/index.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title, @date.to_formatted_s(:full) %> 2 | 3 |
4 |
5 | <%= render "shared/components/list", title: "Exercise", path: new_exercise_entry_path do %> 6 | <% @exercise_entries.each do |entry| %> 7 | <%= render "shared/components/list/item", title: entry.name %> 8 | <% end %> 9 | <% end %> 10 | 11 | <%= render "shared/components/list", title: "Medication & supplements", path: new_medication_entry_path do %> 12 | <% @medication_entries.each do |entry| %> 13 | <%= render "shared/components/list/item", title: entry.name %> 14 | <% end %> 15 | <% end %> 16 | 17 | <%= render "shared/components/list", title: "Water", path: "#" do %> 18 | <%= render "shared/components/list/item", title: "#{@water} oz" %> 19 | <% end %> 20 |
21 | 22 |
23 | <%= render "shared/components/list", title: "Food", path: "#" do %> 24 | <% @food_entries.each do |entry| %> 25 | <%= render "shared/components/list/item", title: entry.name, out: entry.out? %> 26 | <% end %> 27 | <% end %> 28 |
29 |
30 | -------------------------------------------------------------------------------- /rails/app/views/days/show.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title, @date.to_formatted_s(:full) %> 2 | <% content_for :header_navigation, render("days/navigation", date: @date) %> 3 | 4 |
5 |
6 | <%= render "shared/components/list", title: "Exercise", path: new_exercise_entry_path(date: @date) do %> 7 | <% @exercise_entries.each do |entry| %> 8 | <%= render "shared/components/list/item", title: entry.name, href: edit_exercise_entry_path(entry) %> 9 | <% end %> 10 | <% end %> 11 | 12 | <%= render "shared/components/list", title: "Medication & supplements", path: new_medication_entry_path(date: @date) do %> 13 | <% @medication_entries.each do |entry| %> 14 | <%= render "shared/components/list/item", title: entry.name, href: edit_medication_entry_path(entry) %> 15 | <% end %> 16 | <% end %> 17 | 18 | <%= render "shared/components/list", title: "Water", path: new_water_entry_path(date: @date) do %> 19 | <%= render "shared/components/list/item", title: "#{@water.value.round} #{@water.unit.name}" %> 20 | <% end %> 21 |
22 | 23 |
24 | <%= render "shared/components/list", title: "Food", path: new_food_entry_path(date: @date) do %> 25 | <% @food_entries.each do |entry| %> 26 | <%= render "shared/components/list/item", title: entry.name, href: edit_food_entry_path(entry), out: entry.out? %> 27 | <% end %> 28 | <% end %> 29 |
30 |
31 | 32 | <%= link_to "Settings", settings_path, 33 | "data-controller": "bridge--button", 34 | "data-bridge-ios-image": "person.circle", 35 | "data-bridge-side": "left", 36 | class: "btn-secondary w-full mt-8 non-turbo-native:hidden" 37 | %> 38 | -------------------------------------------------------------------------------- /rails/app/views/exercise_entries/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%# locals: (entry:, date:) %> 2 | 3 | <% if entry.errors.any? %> 4 | <%= render "shared/components/form/errors", name: "exercise", errors: entry.errors %> 5 | <% end %> 6 | 7 | <%= strada_form_with model: entry, html: {data: {"turbo-action": "replace"}}, class: "max-w-lg mx-auto" do |form| %> 8 |
9 |
10 | <%= form.label :name, "What did you do?", class: "form-label" %> 11 | <%= form.text_field :name, class: "form-input" %> 12 |
13 |
14 | <%= form.label :occurred_on, "When?", class: "form-label" %> 15 | <%= form.date_field :occurred_on, value: date, class: "form-input" %> 16 |
17 |
18 |
19 | <%= form.submit "Save", class: "btn-primary" %> 20 |
21 | <% end %> 22 | -------------------------------------------------------------------------------- /rails/app/views/exercise_entries/edit.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title, "Edit exercise entry" %> 2 | 3 | <%= render "form", entry: @entry, date: @date %> 4 | -------------------------------------------------------------------------------- /rails/app/views/exercise_entries/new.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title, "New exercise entry" %> 2 | 3 | <%= render "form", entry: @entry, date: @date %> 4 | -------------------------------------------------------------------------------- /rails/app/views/food_entries/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%# locals: (entry:, date:) %> 2 | 3 | <% if entry.errors.any? %> 4 | <%= render "shared/components/form/errors", name: "food", errors: entry.errors %> 5 | <% end %> 6 | 7 | <%= strada_form_with model: entry, html: {data: {"turbo-action": "replace"}}, class: "max-w-lg mx-auto" do |form| %> 8 |
9 |
10 | <%= form.label :name, "What did you eat?", class: "form-label" %> 11 | <%= form.text_field :name, class: "form-input" %> 12 |
13 |
14 | <%= form.label :occurred_on, "When?", class: "form-label" %> 15 | <%= form.date_field :occurred_on, value: date, class: "form-input" %> 16 |
17 |
18 | <%= form.check_box :out, class: "form-checkbox" %> 19 | <%= form.label :out, "Did you eat this meal out?", class: "form-label" %> 20 |
21 |
22 |
23 | <%= form.submit "Save", class: "btn-primary" %> 24 |
25 | <% end %> 26 | -------------------------------------------------------------------------------- /rails/app/views/food_entries/edit.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title, "Edit food entry" %> 2 | 3 | <%= render "form", entry: @entry, date: @date %> 4 | -------------------------------------------------------------------------------- /rails/app/views/food_entries/new.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title, "New food entry" %> 2 | 3 | <%= render "form", entry: @entry, date: @date %> 4 | -------------------------------------------------------------------------------- /rails/app/views/home/show.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |

A better way to track what matters

4 |

Exercising, eating real food, and drinking plenty of water contribute to a healthy life. The Daily Log app helps you keep track. Every day.

5 |
6 | <%= link_to "Get started", new_user_path, class: "btn-primary px-3.5 py-2.5" %> 7 | <%= link_to "https://apps.apple.com/us/app/daily-log-app/id6473819686", class: "turbo-native:hidden" do %> 8 | <%= image_tag "app_store.png", class: "h-10" %> 9 | <% end %> 10 |
11 |
12 |
13 | <%= image_tag "screenshots/ios.png", class: "mx-auto w-[22.875rem] max-w-full drop-shadow-xl", alt: "Screenshot of the Daily Log app running on an iPhone." %> 14 |
15 |
16 | -------------------------------------------------------------------------------- /rails/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | class="h-full bg-white"> 3 | 4 | <%= page_title %> 5 | 6 | 7 | <%= csrf_meta_tags %> 8 | <%= csp_meta_tag %> 9 | <%= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload" %> 10 | <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %> 11 | <%= javascript_importmap_tags %> 12 | <%= analytics_tag %> 13 | 14 | 15 | 16 | <%= render "shared/header", title: page_title %> 17 | <%= render "shared/flash" %> 18 |
19 |
20 | <%= yield %> 21 |
22 |
23 | <%= track_page_view_script %> 24 | 25 | 26 | -------------------------------------------------------------------------------- /rails/app/views/layouts/mailer.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | -------------------------------------------------------------------------------- /rails/app/views/layouts/mailer.text.erb: -------------------------------------------------------------------------------- 1 | <%= yield %> 2 | -------------------------------------------------------------------------------- /rails/app/views/medication_entries/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%# locals: (entry:, date:) %> 2 | 3 | <% if entry.errors.any? %> 4 | <%= render "shared/components/form/errors", name: "medication", errors: entry.errors %> 5 | <% end %> 6 | 7 | <%= strada_form_with model: entry, html: {data: {"turbo-action": "replace"}}, class: "max-w-lg mx-auto" do |form| %> 8 |
9 |
10 | <%= form.label :name, "What did you take?", class: "form-label" %> 11 | <%= form.text_field :name, class: "form-input" %> 12 |
13 |
14 | <%= form.label :occurred_on, "When?", class: "form-label" %> 15 | <%= form.date_field :occurred_on, value: date, class: "form-input" %> 16 |
17 |
18 |
19 | <%= form.submit "Save", class: "btn-primary" %> 20 |
21 | <% end %> 22 | -------------------------------------------------------------------------------- /rails/app/views/medication_entries/edit.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title, "Edit medication entry" %> 2 | 3 | <%= render "form", entry: @entry, date: @date %> 4 | -------------------------------------------------------------------------------- /rails/app/views/medication_entries/new.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title, "New medication entry" %> 2 | 3 | <%= render "form", entry: @entry, date: @date %> 4 | -------------------------------------------------------------------------------- /rails/app/views/sessions/new.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :turbo_native_title, "Sign in" %> 2 | 3 |
4 |
5 |

Sign in to your account

6 |
7 |
8 | <%= strada_form_with url: session_path, html: {"data-turbo-action": "replace"}, class: "space-y-6" do |form| %> 9 |
10 | <%= form.label :email, "Email address", class: "form-label" %> 11 | <%= form.email_field :email, autocomplete: "email", required: true, class: "form-input" %> 12 |
13 |
14 | <%= form.label :password, class: "form-label" %> 15 | <%= form.password_field :password, autocomplete: "current-password", required: true, class: "form-input" %> 16 |
17 |
18 | <%= form.submit "Sign in", class: "btn-primary w-full" %> 19 |
20 | <% end %> 21 |

Not a member? <%= link_to "Create an account", new_user_path, class: "font-semibold leading-6 text-primary-600 hover:text-primary-500" %>

22 |
23 |
24 | -------------------------------------------------------------------------------- /rails/app/views/settings/edit.html.erb: -------------------------------------------------------------------------------- 1 | <%= content_for :title, "Settings" %> 2 | 3 | <% if @settings.errors.any? %> 4 | <%= render "shared/components/form/errors", name: "settings", errors: @settings.errors %> 5 | <% end %> 6 | 7 | <%= strada_form_with model: @settings, url: settings_path, as: :settings, html: {data: {"turbo-action": "replace"}}, class: "max-w-lg mx-auto" do |form| %> 8 |
9 |
10 | Measurement system 11 |

Show entries in this system and set unit for new measurements.

12 |
13 |
14 |
15 | <%= form.radio_button :measurement_system, :imperial, class: "form-radio" %> 16 |
17 |
18 | <%= form.label :measurement_system_imperial, "Imperial", class: "form-label" %> 19 |

Use ounces (oz) for water entries.

20 |
21 |
22 |
23 |
24 | <%= form.radio_button :measurement_system, :metric, class: "form-radio" %> 25 |
26 |
27 | <%= form.label :measurement_system_metric, "Metric", class: "form-label" %> 28 |

Use milliliters (ml) for water entries.

29 |
30 |
31 |
32 |
33 |
34 | <%= form.label :time_zone, class: "form-label" %> 35 | <%= form.time_zone_select :time_zone, ActiveSupport::TimeZone.us_zones, {}, class: "form-select" %> 36 |
37 |
38 |
39 | <%= form.submit "Save", class: "btn-primary" %> 40 |
41 | <% end %> 42 | 43 |
44 |
45 | <%= button_to "Sign out", session_path, method: :delete, "data-turbo-action": "replace", class: "btn-secondary w-full" %> 46 |

Delete account

47 |

This action is not reversible. All information related to this account will be deleted permanently.

48 | <%= button_to "Delete my account", user_path(current_user), method: :delete, "data-turbo-action": "replace", "data-turbo-confirm": "Are you sure you want to delete your account?", class: "btn-secondary text-red-500 ring-red-200 hover:bg-red-50 mt-4" %> 49 |
50 | -------------------------------------------------------------------------------- /rails/app/views/shared/_flash.html.erb: -------------------------------------------------------------------------------- 1 | <% if alert = flash.alert %> 2 |
3 |
4 |
5 |
6 | <%= inline_svg "icons/mini/x_circle.svg", class: "h-5 w-5 text-red-400" %> 7 |
8 |
9 |

<%= alert %>

10 |
11 |
12 |
13 |
14 | <% end %> 15 | 16 | <% if notice = flash.notice %> 17 |
18 |
19 |
20 |
21 | <%= inline_svg "icons/mini/check_circle.svg", class: "h-5 w-5 text-green-400" %> 22 |
23 |
24 |

<%= notice %>

25 |
26 |
27 |
28 |
29 | <% end %> 30 | -------------------------------------------------------------------------------- /rails/app/views/shared/_header.html.erb: -------------------------------------------------------------------------------- 1 | <%# locals: (title:) %> 2 | 3 |
4 |
5 |
6 |
7 | <%= link_to root_path do %> 8 | Daily Log 9 | <%= inline_svg "logo.svg", class: "h-8 sm:h-10 w-auto text-gray-600" %> 10 | <% end %> 11 |

<%= title %>

12 | <%= content_for :header_navigation %> 13 |
14 | <% if user_signed_in? %> 15 | <%= link_to settings_path, class: "rounded-md bg-white px-3 py-2 text-gray-900 hover:bg-gray-50" do %> 16 | <%= inline_svg "icons/outline/user_circle.svg", class: "w-6 h-6" %> 17 | Settings 18 | <% end %> 19 | <% else %> 20 | 21 | <%= inline_svg "github.svg", class: "-ml-0.5 h-5 w-5" %> 22 | Fork me on GitHub 23 | 24 | <% end %> 25 |
26 |
27 |
28 | -------------------------------------------------------------------------------- /rails/app/views/shared/components/_list.html.erb: -------------------------------------------------------------------------------- 1 | <%# locals: (title:, path:) %> 2 | 3 |
4 | <%= render "shared/components/list/header", title:, path: %> 5 |
    6 | <%= yield %> 7 |
8 |
9 | -------------------------------------------------------------------------------- /rails/app/views/shared/components/form/_errors.html.erb: -------------------------------------------------------------------------------- 1 | <%# locals: (name:, errors:) %> 2 | 3 |
4 |
5 |
6 | <%= inline_svg "icons/mini/x_circle.svg", class: "h-5 w-5 text-red-400" %> 7 |
8 |
9 |

Please fix these issues to add your <%= name %>:

10 |
11 |
    12 | <% errors.each do |error| %> 13 |
  • <%= error.full_message %>
  • 14 | <% end %> 15 |
16 |
17 |
18 |
19 |
20 | -------------------------------------------------------------------------------- /rails/app/views/shared/components/list/_header.html.erb: -------------------------------------------------------------------------------- 1 | <%# locals: (title:, path:) %> 2 | 3 |
4 |
5 |
6 |

<%= title %>

7 |
8 | <%= link_to path, class: "rounded-full bg-primary-600 p-1.5 text-white shadow-sm hover:bg-primary-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-600 mt-2" do %> 9 | <%= inline_svg "icons/mini/plus.svg", class: "w-5 h-5" %> 10 | <% end %> 11 |
12 |
13 | -------------------------------------------------------------------------------- /rails/app/views/shared/components/list/_item.html.erb: -------------------------------------------------------------------------------- 1 | <%# locals: (title:, href: nil, out: false) %> 2 | 3 |
  • "> 4 |
    5 |
    6 | <% if href.present? %> 7 | <%= link_to href do %> 8 | 9 | <%= title %> 10 | <% end %> 11 | <% else %> 12 | <%= title %> 13 | <% end %> 14 |
    15 |
    16 |
    17 | <% if out %> 18 | Out 19 | <% end %> 20 |
    21 |
  • 22 | -------------------------------------------------------------------------------- /rails/app/views/users/new.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :turbo_native_title, "Create an account" %> 2 | 3 | <% if @user.errors.any? %> 4 | <%= render "shared/components/form/errors", name: "account", errors: @user.errors %> 5 | <% end %> 6 | 7 |
    8 |
    9 |

    Create an account

    10 |
    11 |
    12 | <%= strada_form_with model: @user, html: {"data-turbo-action": "replace"}, class: "space-y-6" do |form| %> 13 |
    14 | <%= form.label :email, "Email address", class: "form-label" %> 15 | <%= form.email_field :email, autocomplete: "email", required: true, class: "form-input" %> 16 |
    17 |
    18 | <%= form.label :password, class: "form-label" %> 19 | <%= form.password_field :password, autocomplete: "new-password", required: true, class: "form-input" %> 20 |
    21 |
    22 | <%= form.label :password_confirmation, "Confirm password", class: "form-label" %> 23 | <%= form.password_field :password_confirmation, autocomplete: "new-password", required: true, class: "form-input" %> 24 |
    25 |
    26 | <%= form.submit "Create account", "data-bridge-title": "Register", class: "btn-primary w-full" %> 27 |
    28 | <% end %> 29 |

    Already have an account? <%= link_to "Sign in", new_session_path, class: "font-semibold leading-6 text-primary-600 hover:text-primary-500" %>

    30 |
    31 |
    32 | -------------------------------------------------------------------------------- /rails/app/views/water_entries/new.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title, "New water entry" %> 2 | 3 | <% if @entry.errors.any? %> 4 | <%= render "shared/components/form/errors", name: "water", errors: @entry.errors %> 5 | <% end %> 6 | 7 |
    8 | <%= strada_form_with model: @entry, html: {"data-turbo-action": "replace"} do |form| %> 9 |
    10 |
    11 | <%= form.label :amount_value, "Amount", class: "form-label" %> 12 |
    13 | <%= form.number_field :amount_value, min: 1, value: nil, class: "form-input pr-14" %> 14 |
    15 | <%= form.label :amount_unit, class: "sr-only" %> 16 | <%= form.select :amount_unit, WaterEntry.units.values, {selected: current_user.settings.water_unit}, class: "h-full rounded-md border-0 bg-transparent py-0 pl-2 pr-7 text-gray-500 focus:ring-2 focus:ring-inset focus:ring-primary-600 sm:text-sm" %> 17 |
    18 |
    19 |
    20 |
    21 | <%= form.label :occurred_on, "When?", class: "form-label" %> 22 | <%= form.date_field :occurred_on, value: @date, class: "form-input" %> 23 |
    24 |
    25 |
    26 | <%= form.submit "Save", class: "btn-primary" %> 27 |
    28 | <% end %> 29 | 30 | <% if @recent_entries.any? %> 31 |
    32 |

    Recent entries

    33 |

    Tap to add.

    34 |
    35 |
    36 | <% @recent_entries.each do |entry| %> 37 |
    38 |
    39 | <%= form_with model: @entry, html: {"data-turbo-action": "replace"} do |form| %> 40 | <%= form.hidden_field :amount_value, value: entry.amount_value %> 41 | <%= form.hidden_field :amount_unit, value: entry.amount_unit %> 42 | <%= form.hidden_field :occurred_on, value: @date %> 43 | <%= form.button type: "submit", class: "focus:outline-none" do %> 44 | 45 |

    <%= entry.amount %>

    46 | <% end %> 47 | <% end %> 48 |
    49 |
    50 | <% end %> 51 |
    52 | <% end %> 53 |
    54 | -------------------------------------------------------------------------------- /rails/bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'bundle' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "rubygems" 12 | 13 | m = Module.new do 14 | module_function 15 | 16 | def invoked_as_script? 17 | File.expand_path($0) == File.expand_path(__FILE__) 18 | end 19 | 20 | def env_var_version 21 | ENV["BUNDLER_VERSION"] 22 | end 23 | 24 | def cli_arg_version 25 | return unless invoked_as_script? # don't want to hijack other binstubs 26 | return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update` 27 | bundler_version = nil 28 | update_index = nil 29 | ARGV.each_with_index do |a, i| 30 | if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN 31 | bundler_version = a 32 | end 33 | next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/o 34 | bundler_version = $1 35 | update_index = i 36 | end 37 | bundler_version 38 | end 39 | 40 | def gemfile 41 | gemfile = ENV["BUNDLE_GEMFILE"] 42 | return gemfile if gemfile && !gemfile.empty? 43 | 44 | File.expand_path("../Gemfile", __dir__) 45 | end 46 | 47 | def lockfile 48 | lockfile = 49 | case File.basename(gemfile) 50 | when "gems.rb" then gemfile.sub(/\.rb$/, ".locked") 51 | else "#{gemfile}.lock" 52 | end 53 | File.expand_path(lockfile) 54 | end 55 | 56 | def lockfile_version 57 | return unless File.file?(lockfile) 58 | lockfile_contents = File.read(lockfile) 59 | return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/o 60 | Regexp.last_match(1) 61 | end 62 | 63 | def bundler_requirement 64 | @bundler_requirement ||= 65 | env_var_version || 66 | cli_arg_version || 67 | bundler_requirement_for(lockfile_version) 68 | end 69 | 70 | def bundler_requirement_for(version) 71 | return "#{Gem::Requirement.default}.a" unless version 72 | 73 | bundler_gem_version = Gem::Version.new(version) 74 | 75 | bundler_gem_version.approximate_recommendation 76 | end 77 | 78 | def load_bundler! 79 | ENV["BUNDLE_GEMFILE"] ||= gemfile 80 | 81 | activate_bundler 82 | end 83 | 84 | def activate_bundler 85 | gem_error = activation_error_handling do 86 | gem "bundler", bundler_requirement 87 | end 88 | return if gem_error.nil? 89 | require_error = activation_error_handling do 90 | require "bundler/version" 91 | end 92 | return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION)) 93 | warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`" 94 | exit 42 95 | end 96 | 97 | def activation_error_handling 98 | yield 99 | nil 100 | rescue StandardError, LoadError => e 101 | e 102 | end 103 | end 104 | 105 | m.load_bundler! 106 | 107 | if m.invoked_as_script? 108 | load Gem.bin_path("bundler", "bundle") 109 | end 110 | -------------------------------------------------------------------------------- /rails/bin/dev: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | if command -v overmind &> /dev/null; then 4 | overmind start -f Procfile.dev 5 | else 6 | if ! gem list foreman -i --silent; then 7 | echo "Installing foreman..." 8 | gem install foreman 9 | fi 10 | 11 | foreman start -f Procfile.dev 12 | fi 13 | -------------------------------------------------------------------------------- /rails/bin/docker-entrypoint: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # If running the rails server then create or migrate existing database 4 | if [ "${*}" == "./bin/rails server" ]; then 5 | ./bin/rails db:prepare 6 | fi 7 | 8 | exec "${@}" 9 | -------------------------------------------------------------------------------- /rails/bin/importmap: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require_relative "../config/application" 4 | require "importmap/commands" 5 | -------------------------------------------------------------------------------- /rails/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path("../config/application", __dir__) 3 | require_relative "../config/boot" 4 | require "rails/commands" 5 | -------------------------------------------------------------------------------- /rails/bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative "../config/boot" 3 | require "rake" 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /rails/bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require "fileutils" 3 | 4 | # path to your application root. 5 | APP_ROOT = File.expand_path("..", __dir__) 6 | 7 | def system!(*) 8 | system(*, exception: true) 9 | end 10 | 11 | FileUtils.chdir APP_ROOT do 12 | # This script is a way to set up or update your development environment automatically. 13 | # This script is idempotent, so that you can run it at any time and get an expectable outcome. 14 | # Add necessary setup steps to this file. 15 | 16 | puts "== Installing dependencies ==" 17 | system! "gem install bundler --conservative" 18 | system("bundle check") || system!("bundle install") 19 | 20 | puts "\n== Preparing database ==" 21 | system! "bin/rails db:prepare" 22 | 23 | puts "\n== Removing old logs and tempfiles ==" 24 | system! "bin/rails log:clear tmp:clear" 25 | 26 | puts "\n== Restarting application server ==" 27 | system! "bin/rails restart" 28 | end 29 | -------------------------------------------------------------------------------- /rails/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require_relative "config/environment" 4 | 5 | run Rails.application 6 | Rails.application.load_server 7 | -------------------------------------------------------------------------------- /rails/config/application.rb: -------------------------------------------------------------------------------- 1 | require_relative "boot" 2 | 3 | require "rails/all" 4 | 5 | # Require the gems listed in Gemfile, including any gems 6 | # you've limited to :test, :development, or :production. 7 | Bundler.require(*Rails.groups) 8 | 9 | module DailyLog 10 | class Application < Rails::Application 11 | # Initialize configuration defaults for originally generated Rails version. 12 | config.load_defaults 7.1 13 | 14 | # Please, add to the `ignore` list any other `lib` subdirectories that do 15 | # not contain `.rb` files, or that should not be reloaded or eager loaded. 16 | # Common ones are `templates`, `generators`, or `middleware`, for example. 17 | config.autoload_lib(ignore: %w[assets tasks]) 18 | 19 | config.time_zone = "Pacific Time (US & Canada)" 20 | config.fathom = config_for(:fathom) 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /rails/config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) 2 | 3 | require "bundler/setup" # Set up gems listed in the Gemfile. 4 | require "bootsnap/setup" # Speed up boot time by caching expensive operations. 5 | -------------------------------------------------------------------------------- /rails/config/cable.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: redis 3 | url: redis://localhost:6379/1 4 | 5 | test: 6 | adapter: test 7 | 8 | production: 9 | adapter: redis 10 | url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> 11 | channel_prefix: daily_log_production 12 | -------------------------------------------------------------------------------- /rails/config/credentials/production.yml.enc: -------------------------------------------------------------------------------- 1 | no6bSQK8162ReV5sdMG4A6PMFc6AObogly7rit70BQp91YMestkcB8GoiBjdr0ESLfjBzanPTI/do6SddEbwVeUglQZha5yXNuurxX6siHlg/u0+bu0tFr983poHRVm1LMhnJ8FSW+XV6lGWm7n05tqs2fB/47xtTljH8HB75nbT/r8Akuw8S2ev+ZMalAsLksXWSTM9ko1GjJ5jonhA4YTmfclirZHXLhJzVc4n17hLEYeUK82kmQ21ivQNR16txvR61U7AOmj1XNBqUfn4rDdZDDVA62tWwvx4sE6ARzhNGTPMJHegQAVxTuGufJbqbFcIF5bQhTkqG7x5mSvSqeNPVZ7T0RbeFxl/IAs8NBdRPhrUcJdXq6ozY9X6PsNrMCIsRWs7Wnw42aW4nVP6VlKUvgygjjvi/PR1yphLzoE40I94FXV96/rR41feKehCVIMnGfO//KtTX83TBJoUhJk8goKXIYZ12boDy45jm8jrdNp0Nvh/0qGN1ZL1gVevwub1fsMGQzCazkXMZx8u4A7VNIPdNUw5iO78q0m4JTGFzLu6eIVH/NGToL+El10oJH8FYMZKbbM/NHNd/NHlvf5klDJzzyDuh67RN/XIg327o7s5P96soBv+7C3reTMPq8Y12VhOgV1Bs703SVXAy3ErTDjAsA==--cg5kLUGfbwWpBgDs--qMQjp7KWtCUbSV5LE9I4Ow== -------------------------------------------------------------------------------- /rails/config/database.yml: -------------------------------------------------------------------------------- 1 | default: &default 2 | adapter: postgresql 3 | encoding: unicode 4 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> 5 | 6 | development: 7 | <<: *default 8 | database: daily_log_development 9 | 10 | # Warning: The database defined as "test" will be erased and 11 | # re-generated from your development database when you run "rake". 12 | # Do not set this db to the same as development or production. 13 | test: 14 | <<: *default 15 | database: daily_log_test 16 | 17 | production: 18 | <<: *default 19 | url: <%= ENV["DATABASE_URL"] %> 20 | -------------------------------------------------------------------------------- /rails/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative "application" 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /rails/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | require "active_support/core_ext/integer/time" 2 | 3 | Rails.application.configure do 4 | # Settings specified here will take precedence over those in config/application.rb. 5 | 6 | # In the development environment your application's code is reloaded any time 7 | # it changes. This slows down response time but is perfect for development 8 | # since you don't have to restart the web server when you make code changes. 9 | config.enable_reloading = true 10 | 11 | # Do not eager load code on boot. 12 | config.eager_load = false 13 | 14 | # Show full error reports. 15 | config.consider_all_requests_local = true 16 | 17 | # Enable server timing 18 | config.server_timing = true 19 | 20 | # Enable/disable caching. By default caching is disabled. 21 | # Run rails dev:cache to toggle caching. 22 | if Rails.root.join("tmp/caching-dev.txt").exist? 23 | config.action_controller.perform_caching = true 24 | config.action_controller.enable_fragment_cache_logging = true 25 | 26 | config.cache_store = :memory_store 27 | config.public_file_server.headers = { 28 | "Cache-Control" => "public, max-age=#{2.days.to_i}" 29 | } 30 | else 31 | config.action_controller.perform_caching = false 32 | 33 | config.cache_store = :null_store 34 | end 35 | 36 | # Store uploaded files on the local file system (see config/storage.yml for options). 37 | config.active_storage.service = :local 38 | 39 | # Don't care if the mailer can't send. 40 | config.action_mailer.raise_delivery_errors = false 41 | 42 | config.action_mailer.perform_caching = false 43 | 44 | # Print deprecation notices to the Rails logger. 45 | config.active_support.deprecation = :log 46 | 47 | # Raise exceptions for disallowed deprecations. 48 | config.active_support.disallowed_deprecation = :raise 49 | 50 | # Tell Active Support which deprecation messages to disallow. 51 | config.active_support.disallowed_deprecation_warnings = [] 52 | 53 | # Raise an error on page load if there are pending migrations. 54 | config.active_record.migration_error = :page_load 55 | 56 | # Highlight code that triggered database queries in logs. 57 | config.active_record.verbose_query_logs = true 58 | 59 | # Highlight code that enqueued background job in logs. 60 | config.active_job.verbose_enqueue_logs = true 61 | 62 | # Suppress logger output for asset requests. 63 | config.assets.quiet = true 64 | 65 | # Raise error when a before_action's only/except options reference missing actions 66 | config.action_controller.raise_on_missing_callback_actions = true 67 | 68 | # Hard code encryption keys for development. 69 | config.active_record.encryption.primary_key = "Ug0Kcv4V42qxUoyeYCoOPExVgkh20ESP" 70 | config.active_record.encryption.deterministic_key = "TBvTnYPf4HrlMOL3uNHQ8td4ebYCcEXT" 71 | config.active_record.encryption.key_derivation_salt = "VHrEcgBVhxRImXqws7yqOA8iF3HuuUST" 72 | end 73 | -------------------------------------------------------------------------------- /rails/config/environments/production.rb: -------------------------------------------------------------------------------- 1 | require "active_support/core_ext/integer/time" 2 | 3 | Rails.application.configure do 4 | # Settings specified here will take precedence over those in config/application.rb. 5 | 6 | # Code is not reloaded between requests. 7 | config.enable_reloading = false 8 | 9 | # Eager load code on boot. This eager loads most of Rails and 10 | # your application in memory, allowing both threaded web servers 11 | # and those relying on copy on write to perform better. 12 | # Rake tasks automatically ignore this option for performance. 13 | config.eager_load = true 14 | 15 | # Full error reports are disabled and caching is turned on. 16 | config.consider_all_requests_local = false 17 | config.action_controller.perform_caching = true 18 | 19 | # Ensures that a master key has been made available in ENV["RAILS_MASTER_KEY"], config/master.key, or an environment 20 | # key such as config/credentials/production.key. This key is used to decrypt credentials (and other encrypted files). 21 | config.require_master_key = true 22 | 23 | # Do not fallback to assets pipeline if a precompiled asset is missed. 24 | config.assets.compile = false 25 | 26 | # Store uploaded files on the local file system (see config/storage.yml for options). 27 | config.active_storage.service = :local 28 | 29 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 30 | config.force_ssl = true 31 | 32 | # Log to STDOUT by default 33 | config.logger = ActiveSupport::Logger.new($stdout) 34 | .tap { |logger| logger.formatter = ::Logger::Formatter.new } 35 | .then { |logger| ActiveSupport::TaggedLogging.new(logger) } 36 | 37 | # Prepend all log lines with the following tags. 38 | config.log_tags = [:request_id] 39 | 40 | # Info include generic and useful information about system operation, but avoids logging too much 41 | # information to avoid inadvertent exposure of personally identifiable information (PII). If you 42 | # want to log everything, set the level to "debug". 43 | config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info") 44 | 45 | # Use a different cache store in production. 46 | # config.cache_store = :mem_cache_store 47 | 48 | # Use a real queuing backend for Active Job (and separate queues per environment). 49 | # config.active_job.queue_adapter = :resque 50 | # config.active_job.queue_name_prefix = "daily_log_production" 51 | 52 | config.action_mailer.perform_caching = false 53 | 54 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 55 | # the I18n.default_locale when a translation cannot be found). 56 | config.i18n.fallbacks = true 57 | 58 | # Don't log any deprecations. 59 | config.active_support.report_deprecations = false 60 | 61 | # Do not dump schema after migrations. 62 | config.active_record.dump_schema_after_migration = false 63 | end 64 | -------------------------------------------------------------------------------- /rails/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | require "active_support/core_ext/integer/time" 2 | 3 | # The test environment is used exclusively to run your application's 4 | # test suite. You never need to work with it otherwise. Remember that 5 | # your test database is "scratch space" for the test suite and is wiped 6 | # and recreated between test runs. Don't rely on the data there! 7 | 8 | Rails.application.configure do 9 | # Settings specified here will take precedence over those in config/application.rb. 10 | 11 | # While tests run files are not watched, reloading is not necessary. 12 | config.enable_reloading = false 13 | 14 | # Eager loading loads your entire application. When running a single test locally, 15 | # this is usually not necessary, and can slow down your test suite. However, it's 16 | # recommended that you enable it in continuous integration systems to ensure eager 17 | # loading is working properly before deploying your code. 18 | config.eager_load = ENV["CI"].present? 19 | 20 | # Configure public file server for tests with Cache-Control for performance. 21 | config.public_file_server.enabled = true 22 | config.public_file_server.headers = { 23 | "Cache-Control" => "public, max-age=#{1.hour.to_i}" 24 | } 25 | 26 | # Show full error reports and disable caching. 27 | config.consider_all_requests_local = true 28 | config.action_controller.perform_caching = false 29 | config.cache_store = :null_store 30 | 31 | # Render exception templates for rescuable exceptions and raise for other exceptions. 32 | config.action_dispatch.show_exceptions = :rescuable 33 | 34 | # Disable request forgery protection in test environment. 35 | config.action_controller.allow_forgery_protection = false 36 | 37 | # Store uploaded files on the local file system in a temporary directory. 38 | config.active_storage.service = :test 39 | 40 | config.action_mailer.perform_caching = false 41 | 42 | # Tell Action Mailer not to deliver emails to the real world. 43 | # The :test delivery method accumulates sent emails in the 44 | # ActionMailer::Base.deliveries array. 45 | config.action_mailer.delivery_method = :test 46 | 47 | # Print deprecation notices to the stderr. 48 | config.active_support.deprecation = :stderr 49 | 50 | # Raise exceptions for disallowed deprecations. 51 | config.active_support.disallowed_deprecation = :raise 52 | 53 | # Tell Active Support which deprecation messages to disallow. 54 | config.active_support.disallowed_deprecation_warnings = [] 55 | 56 | # Raise error when a before_action's only/except options reference missing actions 57 | config.action_controller.raise_on_missing_callback_actions = true 58 | end 59 | -------------------------------------------------------------------------------- /rails/config/fathom.yml: -------------------------------------------------------------------------------- 1 | development: LLUGOANV 2 | test: XXXXXXXX 3 | production: YCLJDTQQ 4 | -------------------------------------------------------------------------------- /rails/config/honeybadger.yml: -------------------------------------------------------------------------------- 1 | api_key: "<%= Rails.application.credentials.dig(:honeybadger, :api_key) %>" 2 | env: "<%= Rails.env %>" 3 | root: "<%= Rails.root.to_s %>" 4 | development_environments: 5 | - test 6 | - development 7 | debug: false 8 | -------------------------------------------------------------------------------- /rails/config/importmap.rb: -------------------------------------------------------------------------------- 1 | # Pin npm packages by running ./bin/importmap 2 | 3 | pin "application", preload: true 4 | pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true 5 | pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true 6 | pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true 7 | pin_all_from "app/javascript/controllers", under: "controllers" 8 | pin "@hotwired/strada", to: "https://ga.jspm.io/npm:@hotwired/strada@1.0.0-beta1/dist/strada.js" 9 | -------------------------------------------------------------------------------- /rails/config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = "1.0" 5 | -------------------------------------------------------------------------------- /rails/config/initializers/date_formats.rb: -------------------------------------------------------------------------------- 1 | Date::DATE_FORMATS[:full] = "%A, %B %e" # Tuesday, December 5 2 | -------------------------------------------------------------------------------- /rails/config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure parameters to be partially matched (e.g. passw matches password) and filtered from the log file. 4 | # Use this to limit dissemination of sensitive information. 5 | # See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors. 6 | Rails.application.config.filter_parameters += [ 7 | :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn 8 | ] 9 | -------------------------------------------------------------------------------- /rails/config/puma.rb: -------------------------------------------------------------------------------- 1 | # This configuration file will be evaluated by Puma. The top-level methods that 2 | # are invoked here are part of Puma's configuration DSL. For more information 3 | # about methods provided by the DSL, see https://puma.io/puma/Puma/DSL.html. 4 | 5 | # Puma can serve each request in a thread from an internal thread pool. 6 | # The `threads` method setting takes two numbers: a minimum and maximum. 7 | # Any libraries that use thread pools should be configured to match 8 | # the maximum value specified for Puma. Default is set to 5 threads for minimum 9 | # and maximum; this matches the default thread size of Active Record. 10 | max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } 11 | min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } 12 | threads min_threads_count, max_threads_count 13 | 14 | # Specifies that the worker count should equal the number of processors in production. 15 | # if ENV["RAILS_ENV"] == "production" 16 | # require "concurrent-ruby" 17 | # worker_count = Integer(ENV.fetch("WEB_CONCURRENCY") { Concurrent.physical_processor_count }) 18 | # workers worker_count if worker_count > 1 19 | # end 20 | 21 | # Specifies the `worker_timeout` threshold that Puma will use to wait before 22 | # terminating a worker in development environments. 23 | worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" 24 | 25 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000. 26 | port ENV.fetch("PORT") { 3000 } 27 | 28 | # Specifies the `environment` that Puma will run in. 29 | environment ENV.fetch("RAILS_ENV") { "development" } 30 | 31 | # Specifies the `pidfile` that Puma will use. 32 | pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } 33 | 34 | # Allow puma to be restarted by `bin/rails restart` command. 35 | plugin :tmp_restart 36 | -------------------------------------------------------------------------------- /rails/config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | get "/settings", to: "settings#edit", as: :settings 3 | 4 | resource :home, only: :show 5 | resource :session, only: %i[new create destroy] 6 | resource :settings, only: %i[edit update] 7 | 8 | resources :days, only: %i[index show] 9 | resources :exercise_entries, only: %i[new create edit update] 10 | resources :food_entries, only: %i[new create edit update] 11 | resources :medication_entries, only: %i[new create edit update] 12 | resources :users, only: %w[new create destroy] 13 | resources :water_entries, only: %i[new create] 14 | 15 | resources :configurations, only: [] do 16 | get :ios, on: :collection 17 | end 18 | 19 | root "home#show" 20 | end 21 | -------------------------------------------------------------------------------- /rails/config/storage.yml: -------------------------------------------------------------------------------- 1 | test: 2 | service: Disk 3 | root: <%= Rails.root.join("tmp/storage") %> 4 | 5 | local: 6 | service: Disk 7 | root: <%= Rails.root.join("storage") %> 8 | -------------------------------------------------------------------------------- /rails/config/tailwind.config.js: -------------------------------------------------------------------------------- 1 | const defaultTheme = require("tailwindcss/defaultTheme") 2 | const colors = require("tailwindcss/colors") 3 | 4 | module.exports = { 5 | content: [ 6 | "./public/*.html", 7 | "./app/helpers/**/*.rb", 8 | "./app/javascript/**/*.js", 9 | "./app/views/**/*.{erb,haml,html,slim}" 10 | ], 11 | theme: { 12 | extend: { 13 | colors: { 14 | primary: colors.teal, 15 | gray: colors.stone 16 | }, 17 | fontFamily: { 18 | sans: ["Inter var", ...defaultTheme.fontFamily.sans] 19 | } 20 | } 21 | }, 22 | plugins: [ 23 | require("@tailwindcss/aspect-ratio"), 24 | require("@tailwindcss/container-queries"), 25 | require("@tailwindcss/forms"), 26 | require("@tailwindcss/typography"), 27 | ({addVariant}) => { 28 | addVariant("turbo-native", "html[data-turbo-native] &"), 29 | addVariant('non-turbo-native', "html:not([data-turbo-native]) &") 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /rails/db/migrate/20231205220854_create_initial_tables.rb: -------------------------------------------------------------------------------- 1 | class CreateInitialTables < ActiveRecord::Migration[7.1] 2 | def change 3 | create_table :exercise_entries do |t| 4 | t.string :name, null: false 5 | t.date :occurred_on, null: false 6 | 7 | t.timestamps 8 | end 9 | 10 | create_table :medication_entries do |t| 11 | t.string :name, null: false 12 | t.date :occurred_on, null: false 13 | 14 | t.timestamps 15 | end 16 | 17 | create_table :water_entries do |t| 18 | t.integer :amount, null: false, default: 0 19 | t.date :occurred_on, null: false 20 | 21 | t.timestamps 22 | end 23 | 24 | create_table :food_entries do |t| 25 | t.string :name, null: false 26 | t.boolean :out, null: false, default: false 27 | t.date :occurred_on, null: false 28 | 29 | t.timestamps 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /rails/db/migrate/20231206182611_create_users.rb: -------------------------------------------------------------------------------- 1 | class CreateUsers < ActiveRecord::Migration[7.1] 2 | def change 3 | create_table :users do |t| 4 | t.string :email, null: false 5 | t.string :password_digest, null: false 6 | 7 | t.timestamps null: false 8 | end 9 | 10 | add_index :users, :email, unique: true 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /rails/db/migrate/20231206191045_associate_entries_with_users.rb: -------------------------------------------------------------------------------- 1 | class AssociateEntriesWithUsers < ActiveRecord::Migration[7.1] 2 | def change 3 | add_reference :exercise_entries, :user, foreign_key: true, null: false 4 | add_reference :medication_entries, :user, foreign_key: true, null: false 5 | add_reference :water_entries, :user, foreign_key: true, null: false 6 | add_reference :food_entries, :user, foreign_key: true, null: false 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /rails/db/migrate/20231208012710_encrypt_sensitive_data.rb: -------------------------------------------------------------------------------- 1 | class EncryptSensitiveData < ActiveRecord::Migration[7.1] 2 | def change 3 | User.find_each { _1.encrypt } 4 | ExerciseEntry.find_each { _1.encrypt } 5 | FoodEntry.find_each { _1.encrypt } 6 | MedicationEntry.find_each { _1.encrypt } 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /rails/db/migrate/20231211184500_add_settings.rb: -------------------------------------------------------------------------------- 1 | class AddSettings < ActiveRecord::Migration[7.1] 2 | def change 3 | create_table :settings do |t| 4 | t.belongs_to :user, null: false 5 | t.string :time_zone, null: false, default: "Pacific Time (US & Canada)" 6 | 7 | t.timestamps 8 | end 9 | 10 | User.find_each(&:create_settings!) 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /rails/db/migrate/20231212203056_add_units.rb: -------------------------------------------------------------------------------- 1 | class AddUnits < ActiveRecord::Migration[7.1] 2 | def change 3 | add_column :water_entries, :amount_value, :decimal, precision: 10, scale: 2 4 | add_column :water_entries, :amount_unit, :string, limit: 12 5 | 6 | WaterEntry.find_each do |entry| 7 | entry.amount_value = entry.amount_before_type_cast 8 | entry.amount_unit = "oz" 9 | entry.save! 10 | end 11 | 12 | add_column :settings, :measurement_system, :string, null: false, default: "imperial" 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /rails/db/migrate/20231213145459_remove_amount_from_water_entries.rb: -------------------------------------------------------------------------------- 1 | class RemoveAmountFromWaterEntries < ActiveRecord::Migration[7.1] 2 | def change 3 | remove_column :water_entries, :amount, :integer, null: false, default: 0 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /rails/db/schema.rb: -------------------------------------------------------------------------------- 1 | # This file is auto-generated from the current state of the database. Instead 2 | # of editing this file, please use the migrations feature of Active Record to 3 | # incrementally modify your database, and then regenerate this schema definition. 4 | # 5 | # This file is the source Rails uses to define your schema when running `bin/rails 6 | # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to 7 | # be faster and is potentially less error prone than running all of your 8 | # migrations from scratch. Old migrations may fail to apply correctly if those 9 | # migrations use external dependencies or application code. 10 | # 11 | # It's strongly recommended that you check this file into your version control system. 12 | 13 | ActiveRecord::Schema[7.1].define(version: 2023_12_13_145459) do 14 | # These are extensions that must be enabled in order to support this database 15 | enable_extension "plpgsql" 16 | 17 | create_table "exercise_entries", force: :cascade do |t| 18 | t.string "name", null: false 19 | t.date "occurred_on", null: false 20 | t.datetime "created_at", null: false 21 | t.datetime "updated_at", null: false 22 | t.bigint "user_id", null: false 23 | t.index ["user_id"], name: "index_exercise_entries_on_user_id" 24 | end 25 | 26 | create_table "food_entries", force: :cascade do |t| 27 | t.string "name", null: false 28 | t.boolean "out", default: false, null: false 29 | t.date "occurred_on", null: false 30 | t.datetime "created_at", null: false 31 | t.datetime "updated_at", null: false 32 | t.bigint "user_id", null: false 33 | t.index ["user_id"], name: "index_food_entries_on_user_id" 34 | end 35 | 36 | create_table "medication_entries", force: :cascade do |t| 37 | t.string "name", null: false 38 | t.date "occurred_on", null: false 39 | t.datetime "created_at", null: false 40 | t.datetime "updated_at", null: false 41 | t.bigint "user_id", null: false 42 | t.index ["user_id"], name: "index_medication_entries_on_user_id" 43 | end 44 | 45 | create_table "settings", force: :cascade do |t| 46 | t.bigint "user_id", null: false 47 | t.string "time_zone", default: "Pacific Time (US & Canada)", null: false 48 | t.datetime "created_at", null: false 49 | t.datetime "updated_at", null: false 50 | t.string "measurement_system", default: "imperial", null: false 51 | t.index ["user_id"], name: "index_settings_on_user_id" 52 | end 53 | 54 | create_table "users", force: :cascade do |t| 55 | t.string "email", null: false 56 | t.string "password_digest", null: false 57 | t.datetime "created_at", null: false 58 | t.datetime "updated_at", null: false 59 | t.index ["email"], name: "index_users_on_email", unique: true 60 | end 61 | 62 | create_table "water_entries", force: :cascade do |t| 63 | t.date "occurred_on", null: false 64 | t.datetime "created_at", null: false 65 | t.datetime "updated_at", null: false 66 | t.bigint "user_id", null: false 67 | t.decimal "amount_value", precision: 10, scale: 2 68 | t.string "amount_unit", limit: 12 69 | t.index ["user_id"], name: "index_water_entries_on_user_id" 70 | end 71 | 72 | add_foreign_key "exercise_entries", "users" 73 | add_foreign_key "food_entries", "users" 74 | add_foreign_key "medication_entries", "users" 75 | add_foreign_key "water_entries", "users" 76 | end 77 | -------------------------------------------------------------------------------- /rails/db/seeds.rb: -------------------------------------------------------------------------------- 1 | User.find_or_create_by!(email: "user@example.com") do |user| 2 | user.password = "password" 3 | end 4 | -------------------------------------------------------------------------------- /rails/lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joemasilotti/daily-log/2458b5bd901b656fe9e9874c9cdb815c5b0a930c/rails/lib/assets/.keep -------------------------------------------------------------------------------- /rails/lib/tasks/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joemasilotti/daily-log/2458b5bd901b656fe9e9874c9cdb815c5b0a930c/rails/lib/tasks/.keep -------------------------------------------------------------------------------- /rails/log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joemasilotti/daily-log/2458b5bd901b656fe9e9874c9cdb815c5b0a930c/rails/log/.keep -------------------------------------------------------------------------------- /rails/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
    60 |
    61 |

    The page you were looking for doesn't exist.

    62 |

    You may have mistyped the address or the page may have moved.

    63 |
    64 |

    If you are the application owner check the logs for more information.

    65 |
    66 | 67 | 68 | -------------------------------------------------------------------------------- /rails/public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
    60 |
    61 |

    The change you wanted was rejected.

    62 |

    Maybe you tried to change something you didn't have access to.

    63 |
    64 |

    If you are the application owner check the logs for more information.

    65 |
    66 | 67 | 68 | -------------------------------------------------------------------------------- /rails/public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
    60 |
    61 |

    We're sorry, but something went wrong.

    62 |
    63 |

    If you are the application owner check the logs for more information.

    64 |
    65 | 66 | 67 | -------------------------------------------------------------------------------- /rails/public/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joemasilotti/daily-log/2458b5bd901b656fe9e9874c9cdb815c5b0a930c/rails/public/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /rails/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joemasilotti/daily-log/2458b5bd901b656fe9e9874c9cdb815c5b0a930c/rails/public/apple-touch-icon.png -------------------------------------------------------------------------------- /rails/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joemasilotti/daily-log/2458b5bd901b656fe9e9874c9cdb815c5b0a930c/rails/public/favicon.ico -------------------------------------------------------------------------------- /rails/public/robots.txt: -------------------------------------------------------------------------------- 1 | # See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | -------------------------------------------------------------------------------- /rails/storage/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joemasilotti/daily-log/2458b5bd901b656fe9e9874c9cdb815c5b0a930c/rails/storage/.keep -------------------------------------------------------------------------------- /rails/test/application_system_test_case.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class ApplicationSystemTestCase < ActionDispatch::SystemTestCase 4 | driven_by :selenium, using: :chrome, screen_size: [1400, 1400] 5 | end 6 | -------------------------------------------------------------------------------- /rails/test/channels/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joemasilotti/daily-log/2458b5bd901b656fe9e9874c9cdb815c5b0a930c/rails/test/channels/.keep -------------------------------------------------------------------------------- /rails/test/controllers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joemasilotti/daily-log/2458b5bd901b656fe9e9874c9cdb815c5b0a930c/rails/test/controllers/.keep -------------------------------------------------------------------------------- /rails/test/fixtures/files/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joemasilotti/daily-log/2458b5bd901b656fe9e9874c9cdb815c5b0a930c/rails/test/fixtures/files/.keep -------------------------------------------------------------------------------- /rails/test/helpers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joemasilotti/daily-log/2458b5bd901b656fe9e9874c9cdb815c5b0a930c/rails/test/helpers/.keep -------------------------------------------------------------------------------- /rails/test/integration/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joemasilotti/daily-log/2458b5bd901b656fe9e9874c9cdb815c5b0a930c/rails/test/integration/.keep -------------------------------------------------------------------------------- /rails/test/mailers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joemasilotti/daily-log/2458b5bd901b656fe9e9874c9cdb815c5b0a930c/rails/test/mailers/.keep -------------------------------------------------------------------------------- /rails/test/models/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joemasilotti/daily-log/2458b5bd901b656fe9e9874c9cdb815c5b0a930c/rails/test/models/.keep -------------------------------------------------------------------------------- /rails/test/system/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joemasilotti/daily-log/2458b5bd901b656fe9e9874c9cdb815c5b0a930c/rails/test/system/.keep -------------------------------------------------------------------------------- /rails/test/test_helper.rb: -------------------------------------------------------------------------------- 1 | ENV["RAILS_ENV"] ||= "test" 2 | require_relative "../config/environment" 3 | require "rails/test_help" 4 | 5 | module ActiveSupport 6 | class TestCase 7 | # Run tests in parallel with specified workers 8 | parallelize(workers: :number_of_processors) 9 | 10 | # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. 11 | fixtures :all 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /rails/tmp/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joemasilotti/daily-log/2458b5bd901b656fe9e9874c9cdb815c5b0a930c/rails/tmp/.keep -------------------------------------------------------------------------------- /rails/tmp/pids/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joemasilotti/daily-log/2458b5bd901b656fe9e9874c9cdb815c5b0a930c/rails/tmp/pids/.keep -------------------------------------------------------------------------------- /rails/tmp/storage/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joemasilotti/daily-log/2458b5bd901b656fe9e9874c9cdb815c5b0a930c/rails/tmp/storage/.keep -------------------------------------------------------------------------------- /rails/vendor/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joemasilotti/daily-log/2458b5bd901b656fe9e9874c9cdb815c5b0a930c/rails/vendor/.keep -------------------------------------------------------------------------------- /rails/vendor/javascript/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joemasilotti/daily-log/2458b5bd901b656fe9e9874c9cdb815c5b0a930c/rails/vendor/javascript/.keep --------------------------------------------------------------------------------