├── .circleci
└── config.yml
├── .codeclimate.yml
├── .csslintrc
├── .dockerignore
├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .github
├── CODEOWNERS
├── ISSUE_TEMPLATE
│ ├── bug_issue_template.yml
│ ├── docs_issue_template.yml
│ └── feature_request_template.yml
├── PULL_REQUEST_TEMPLATE.md
└── config.yml
├── .gitignore
├── .nvmrc
├── .rspec
├── .rubocop.yml
├── .ruby-gemset
├── .ruby-version
├── .vscode
└── settings.json
├── CONTRIBUTING.md
├── Dockerfile
├── Gemfile
├── Gemfile.lock
├── LICENSE.txt
├── Procfile
├── Procfile.dev
├── README-AR.md
├── README-BN.md
├── README-CN.md
├── README-ES.md
├── README-FA.md
├── README-FR.md
├── README-HI.md
├── README-ID.md
├── README-IT.md
├── README-KO.md
├── README-LK.md
├── README-PT.md
├── README-TR.md
├── README-VI.md
├── README.md
├── Rakefile
├── app
├── assets
│ ├── images
│ │ ├── contributors
│ │ │ ├── Arun_Kumar.jpg
│ │ │ ├── Ghada_AbdulWahab.png
│ │ │ ├── Hassan_Ahmed.png
│ │ │ ├── Krishanu_Shashwat.jpg
│ │ │ ├── Oliver_Ikegah.jpg
│ │ │ ├── Olivia_Robinson.jpg
│ │ │ ├── Sourabh_Yadav.jpg
│ │ │ ├── Zeeshan_Sarwar.png
│ │ │ ├── abe_dolinger.jpeg
│ │ │ ├── adan_amarillas.jpg
│ │ │ ├── alex_fa.jpg
│ │ │ ├── alex_manzo.jpg
│ │ │ ├── alline_marjorie.jpg
│ │ │ ├── angel_quesada.jpg
│ │ │ ├── atibhi_agrawal.jpg
│ │ │ ├── bee_martinez.jpg
│ │ │ ├── ben_pham.jpg
│ │ │ ├── britton_jenner.png
│ │ │ ├── camila_campos.png
│ │ │ ├── carl_summers.jpg
│ │ │ ├── chibuzor_efedigbue.jpeg
│ │ │ ├── claire_wild.jpg
│ │ │ ├── daaimah_tibrey.png
│ │ │ ├── darryl_dixon.jpg
│ │ │ ├── dena_burd.png
│ │ │ ├── desi_rottman.jpg
│ │ │ ├── ellen_macpherson.jpg
│ │ │ ├── emma_smith.png
│ │ │ ├── francisco_perejon.jpeg
│ │ │ ├── george_karametas.png
│ │ │ ├── gurpreet_gill.jpg
│ │ │ ├── haley_mnatzaganian.jpg
│ │ │ ├── hnarasaki.jpg
│ │ │ ├── ingrid_garcia.jpg
│ │ │ ├── irene_li.jpg
│ │ │ ├── irmak_aytekin.jpg
│ │ │ ├── isabelle_yiu.png
│ │ │ ├── jasmine_logan.png
│ │ │ ├── jason_alsip.jpg
│ │ │ ├── jasper_martin.png
│ │ │ ├── jennifer_parsons.jpg
│ │ │ ├── jennifer_shen.jpg
│ │ │ ├── jennifer_winer.jpg
│ │ │ ├── jenny_nam.jpg
│ │ │ ├── jenny_nguyen.jpg
│ │ │ ├── jeremiah_tabb.jpg
│ │ │ ├── john_maguire.png
│ │ │ ├── jon_tan.jpg
│ │ │ ├── julia_nguyen.jpg
│ │ │ ├── julian_macmang.jpg
│ │ │ ├── karolina_benitez.jpg
│ │ │ ├── kelly_sousa.png
│ │ │ ├── lee_mulvey.jpg
│ │ │ ├── liliana_velazquez.jpg
│ │ │ ├── lisette_ruiz.jpg
│ │ │ ├── lucy_yu.jpg
│ │ │ ├── manish_sharma.jpeg
│ │ │ ├── manish_yadav.jpeg
│ │ │ ├── maribel_duran.jpg
│ │ │ ├── miguel_navarrete.png
│ │ │ ├── mohammad_aakash.jpg
│ │ │ ├── muhammad_rahmatullah.jpeg
│ │ │ ├── nagma_kapoor.jpg
│ │ │ ├── nicholas_lee.jpg
│ │ │ ├── nikhil_bhatt.jpg
│ │ │ ├── nishiki_liu.jpg
│ │ │ ├── pedro_paulino.jpg
│ │ │ ├── pierre_monier.jpg
│ │ │ ├── prateksha_udhayanan.jpg
│ │ │ ├── rebecca_taylor.jpg
│ │ │ ├── rizka_luthfiani.jpeg
│ │ │ ├── seun_adekunle.jpg
│ │ │ ├── sonu_toor.jpg
│ │ │ ├── sophie_mcdonald.jpg
│ │ │ ├── srishti_gupta.jpg
│ │ │ ├── stephanie_warmenhoven.jpg
│ │ │ ├── tara_swenson.jpg
│ │ │ ├── tara_wilkins.jpg
│ │ │ ├── ted_vu.jpg
│ │ │ ├── tracy_holmes.png
│ │ │ ├── tyler_walker.jpg
│ │ │ ├── tyler_welsh.jpg
│ │ │ ├── udayan_shevade.png
│ │ │ ├── valeria_kolisnyk.jpg
│ │ │ ├── varshini_ananta.jpg
│ │ │ ├── vilde_vevatne.jpg
│ │ │ └── yuri.jpg
│ │ ├── documents.svg
│ │ ├── favicon.ico
│ │ ├── lotus.svg
│ │ ├── partners
│ │ │ ├── brown_sisters_speak.png
│ │ │ ├── dpga.png
│ │ │ ├── dpga.svg
│ │ │ ├── everybody_has_a_brain.png
│ │ │ ├── hacker_hours.png
│ │ │ ├── mh_prompt.png
│ │ │ ├── osmi.png
│ │ │ ├── rails_girls_summer_of_code.png
│ │ │ ├── seadc.png
│ │ │ └── write_speak_code.png
│ │ ├── phone.svg
│ │ ├── static_page_bottom_bg.svg
│ │ ├── static_page_top_bg.svg
│ │ └── welcome.svg
│ ├── javascripts
│ │ ├── application.js
│ │ └── require_recaptcha.js
│ └── stylesheets
│ │ ├── application.scss
│ │ ├── application
│ │ ├── allies.scss
│ │ ├── contributors.scss
│ │ ├── mailer.scss
│ │ ├── profile.scss
│ │ └── shared.scss
│ │ ├── base
│ │ ├── _animations.scss
│ │ ├── _breakpoints.scss
│ │ ├── _colors.scss
│ │ ├── _fonts.scss
│ │ ├── _margin.scss
│ │ ├── _normalize.scss
│ │ ├── _padding.scss
│ │ ├── _sizes.scss
│ │ └── _values.scss
│ │ ├── core
│ │ ├── alerts.scss
│ │ ├── buttons.scss
│ │ ├── containers.scss
│ │ ├── displays.scss
│ │ ├── errors.scss
│ │ ├── footer.scss
│ │ ├── forms.scss
│ │ ├── grids.scss
│ │ ├── images.scss
│ │ ├── links.scss
│ │ ├── margins.scss
│ │ ├── notices.scss
│ │ └── text.scss
│ │ ├── dashboard
│ │ ├── dashboard.scss
│ │ ├── dashboard_content.scss
│ │ ├── dashboard_nav.scss
│ │ └── dashboard_section.scss
│ │ ├── overrides
│ │ └── font_awesome.scss
│ │ ├── secret_share
│ │ └── secret_share_content.scss
│ │ └── static
│ │ ├── static.scss
│ │ └── static_content.scss
├── controllers
│ ├── allies_controller.rb
│ ├── application_controller.rb
│ ├── care_plan_contacts_controller.rb
│ ├── care_plan_controller.rb
│ ├── categories_controller.rb
│ ├── comments_controller.rb
│ ├── concerns
│ │ ├── care_plan_contacts_concern.rb
│ │ ├── collection_page_setup_concern.rb
│ │ ├── moment_templates_concern.rb
│ │ ├── moments_concern.rb
│ │ ├── page_redirect_concern.rb
│ │ ├── pages_concern.rb
│ │ ├── shared.rb
│ │ ├── shared_basic_concern.rb
│ │ └── strategies_concern.rb
│ ├── errors_controller.rb
│ ├── groups
│ │ └── memberships_controller.rb
│ ├── groups_controller.rb
│ ├── locales_controller.rb
│ ├── medications_controller.rb
│ ├── meetings
│ │ └── google_calendar_event_controller.rb
│ ├── meetings_controller.rb
│ ├── moment_templates_controller.rb
│ ├── moments_controller.rb
│ ├── moods_controller.rb
│ ├── notifications_controller.rb
│ ├── omniauth_callbacks_controller.rb
│ ├── pages_controller.rb
│ ├── profile_controller.rb
│ ├── pusher_controller.rb
│ ├── registrations_controller.rb
│ ├── reports_controller.rb
│ ├── search_controller.rb
│ ├── secret_shares_controller.rb
│ ├── sessions_controller.rb
│ ├── strategies_controller.rb
│ └── users
│ │ ├── invitations_controller.rb
│ │ └── reports_controller.rb
├── helpers
│ ├── application_helper.rb
│ ├── application_mailer_helper.rb
│ ├── assets_helper.rb
│ ├── calendar_helper.rb
│ ├── categories_helper.rb
│ ├── comments_form_helper.rb
│ ├── comments_helper.rb
│ ├── dashboard_nav_helper.rb
│ ├── date_time_helper.rb
│ ├── form_helper.rb
│ ├── group_notification_helper.rb
│ ├── groups_form_helper.rb
│ ├── groups_helper.rb
│ ├── header_helper.rb
│ ├── medication_refill_helper.rb
│ ├── medications_form_helper.rb
│ ├── medications_helper.rb
│ ├── meetings_form_helper.rb
│ ├── meetings_helper.rb
│ ├── moments_form_helper.rb
│ ├── moments_helper.rb
│ ├── moments_stats_helper.rb
│ ├── moods_helper.rb
│ ├── most_focus_helper.rb
│ ├── notification_mailer_helper.rb
│ ├── notifications_helper.rb
│ ├── pages_helper.rb
│ ├── profile_helper.rb
│ ├── reminder_helper.rb
│ ├── reports_helper.rb
│ ├── stories_helper.rb
│ ├── strategies_form_helper.rb
│ ├── strategies_helper.rb
│ ├── tags_helper.rb
│ ├── users
│ │ └── reports_helper.rb
│ ├── viewers_helper.rb
│ └── visible_helper.rb
├── mailers
│ ├── ally_notifications
│ │ ├── accepted_ally_request.rb
│ │ └── new_ally_request.rb
│ ├── application_mailer.rb
│ ├── banned_mailer.rb
│ ├── custom_devise_mailer.rb
│ ├── notification_mailer.rb
│ └── report_mailer.rb
├── models
│ ├── allyship.rb
│ ├── application_record.rb
│ ├── care_plan_contact.rb
│ ├── category.rb
│ ├── comment.rb
│ ├── concerns
│ │ ├── ally_concern.rb
│ │ ├── common_methods.rb
│ │ ├── is_visible_concern.rb
│ │ └── viewer.rb
│ ├── group.rb
│ ├── group_member.rb
│ ├── medication.rb
│ ├── meeting.rb
│ ├── meeting_member.rb
│ ├── moment.rb
│ ├── moment_template.rb
│ ├── moments_category.rb
│ ├── moments_mood.rb
│ ├── moments_strategy.rb
│ ├── mood.rb
│ ├── notification.rb
│ ├── perform_strategy_reminder.rb
│ ├── refill_reminder.rb
│ ├── report.rb
│ ├── strategies_category.rb
│ ├── strategy.rb
│ ├── support.rb
│ ├── take_medication_reminder.rb
│ ├── user.rb
│ ├── users.rb
│ └── users
│ │ └── data_request.rb
├── services
│ ├── allyship_creator.rb
│ ├── allyships
│ │ └── alliance_notifier.rb
│ ├── calendar_uploader.rb
│ ├── cloudinary_service.rb
│ ├── comment_notifications_service.rb
│ ├── comment_viewers_service.rb
│ ├── group_notifier.rb
│ ├── leader_updater.rb
│ ├── medication_reminders.rb
│ ├── medium.rb
│ ├── meeting_notifications_service.rb
│ ├── meeting_reminders.rb
│ ├── moment_keywords.rb
│ ├── profile_picture.rb
│ ├── recaptcha_service.rb
│ ├── resource_recommendations.rb
│ ├── strategy_reminders.rb
│ └── time_ago.rb
├── uploaders
│ └── avatar_uploader.rb
├── views
│ ├── allies
│ │ └── index.html.erb
│ ├── banned_mailer
│ │ ├── add_ban_email.html.erb
│ │ └── remove_ban_email.html.erb
│ ├── care_plan
│ │ └── index.html.erb
│ ├── categories
│ │ ├── _category.html.erb
│ │ ├── edit.html.erb
│ │ ├── index.html.erb
│ │ ├── new.html.erb
│ │ └── show.html.erb
│ ├── devise
│ │ ├── confirmations
│ │ │ └── new.html.erb
│ │ ├── mailer
│ │ │ ├── confirmation_instructions.html.erb
│ │ │ ├── reset_password_instructions.html.erb
│ │ │ └── unlock_instructions.html.erb
│ │ ├── passwords
│ │ │ ├── edit.html.erb
│ │ │ └── new.html.erb
│ │ ├── registrations
│ │ │ ├── edit.html.erb
│ │ │ └── new.html.erb
│ │ ├── sessions
│ │ │ └── new.html.erb
│ │ ├── shared
│ │ │ └── _links.erb
│ │ └── unlocks
│ │ │ └── new.html.erb
│ ├── errors
│ │ ├── internal_server_error.html.erb
│ │ └── not_found.html.erb
│ ├── groups
│ │ ├── _info.html.erb
│ │ ├── _members.html.erb
│ │ ├── edit.html.erb
│ │ ├── index.html.erb
│ │ ├── new.html.erb
│ │ └── show.html.erb
│ ├── layouts
│ │ ├── application.html.erb
│ │ ├── mailer.html.erb
│ │ └── mailer.text.erb
│ ├── medications
│ │ ├── _medication.html.erb
│ │ ├── _story_body.html.erb
│ │ ├── edit.html.erb
│ │ ├── index.html.erb
│ │ ├── new.html.erb
│ │ └── show.html.erb
│ ├── meetings
│ │ ├── _story_body.html.erb
│ │ ├── edit.html.erb
│ │ ├── new.html.erb
│ │ └── show.html.erb
│ ├── moment_templates
│ │ └── index.html.erb
│ ├── moments
│ │ ├── _moment.html.erb
│ │ ├── edit.html.erb
│ │ ├── index.html.erb
│ │ ├── new.html.erb
│ │ └── show.html.erb
│ ├── moods
│ │ ├── _mood.html.erb
│ │ ├── edit.html.erb
│ │ ├── index.html.erb
│ │ ├── new.html.erb
│ │ └── show.html.erb
│ ├── notification_mailer
│ │ ├── meeting_reminder.html.erb
│ │ ├── meeting_reminder.text.erb
│ │ ├── notification_email.html.erb
│ │ ├── notification_email.text.erb
│ │ ├── perform_strategy.html.erb
│ │ ├── perform_strategy.text.erb
│ │ ├── refill_medication.html.erb
│ │ ├── refill_medication.text.erb
│ │ ├── take_medication.html.erb
│ │ └── take_medication.text.erb
│ ├── pages
│ │ ├── _contributor_blurb.html.erb
│ │ ├── _not_signed_in.html.erb
│ │ ├── _signed_in_empty.html.erb
│ │ ├── _update_password_modal.html.erb
│ │ ├── about.html.erb
│ │ ├── admin_dashboard.html.erb
│ │ ├── faq.html.erb
│ │ ├── home.html.erb
│ │ ├── partners.html.erb
│ │ ├── press.html.erb
│ │ ├── privacy.html.erb
│ │ └── resources.html.erb
│ ├── profile
│ │ └── index.html.erb
│ ├── report_mailer
│ │ ├── reported_email.html.erb
│ │ └── reportee_email.html.erb
│ ├── reports
│ │ └── new.html.erb
│ ├── search
│ │ ├── _form.html.erb
│ │ ├── _posts.html.erb
│ │ └── index.html.erb
│ ├── shared
│ │ ├── _comments.html.erb
│ │ ├── _dashboard_nav_actions.html.erb
│ │ ├── _dashboard_nav_links.html.erb
│ │ ├── _dashboard_nav_mobile.html.erb
│ │ ├── _footer.html.erb
│ │ ├── _page_author.html.erb
│ │ ├── _page_title.html.erb
│ │ └── _stats.html.erb
│ ├── stories
│ │ ├── _category_or_mood.html.erb
│ │ └── _moment_or_strategy.html.erb
│ ├── strategies
│ │ ├── _strategy.html.erb
│ │ ├── edit.html.erb
│ │ ├── index.html.erb
│ │ ├── new.html.erb
│ │ └── show.html.erb
│ ├── tag_usage
│ │ ├── _index.html.erb
│ │ └── _stories.html.erb
│ └── users
│ │ ├── invitations
│ │ ├── edit.html.erb
│ │ └── new.html.erb
│ │ └── mailer
│ │ ├── invitation_instructions.html.erb
│ │ └── invitation_instructions.text.erb
└── workers
│ ├── delete_stale_data_worker.rb
│ └── process_data_request_worker.rb
├── bin
├── bundle
├── client.sh
├── install-git-hooks.bash
├── rails
├── rake
├── setup
├── spring
├── start_app
├── update
├── webpack
└── webpack-dev-server
├── client
├── .babelrc
├── .eslintignore
├── .eslintrc
├── .flowconfig
├── .gitignore
├── .prettierrc
├── .storybook
│ ├── deploy.sh
│ ├── main.js
│ ├── preview.js
│ └── stories.scss
├── .stylelintrc
├── app
│ ├── components
│ │ ├── Accordion
│ │ │ ├── __tests__
│ │ │ │ └── Accordion.spec.jsx
│ │ │ └── index.jsx
│ │ ├── Avatar
│ │ │ ├── Avatar.scss
│ │ │ ├── __tests__
│ │ │ │ └── Avatar.spec.jsx
│ │ │ └── index.jsx
│ │ ├── BaseContainer
│ │ │ ├── StoryContainer.jsx
│ │ │ ├── __tests__
│ │ │ │ ├── StoryContainer.spec.jsx
│ │ │ │ └── index.spec.jsx
│ │ │ └── index.jsx
│ │ ├── Blockquote
│ │ │ ├── Blockquote.scss
│ │ │ ├── __tests__
│ │ │ │ └── Blockquote.spec.jsx
│ │ │ └── index.jsx
│ │ ├── Chart
│ │ │ ├── ChartControl.jsx
│ │ │ ├── ChartControl.scss
│ │ │ ├── __tests__
│ │ │ │ ├── Chart.spec.jsx
│ │ │ │ └── ChartControl.spec.jsx
│ │ │ └── index.jsx
│ │ ├── Form
│ │ │ ├── DynamicForm.jsx
│ │ │ ├── Form.scss
│ │ │ ├── __tests__
│ │ │ │ ├── DynamicForm.spec.jsx
│ │ │ │ └── Form.spec.jsx
│ │ │ ├── index.jsx
│ │ │ └── utils.js
│ │ ├── Header
│ │ │ ├── Header.scss
│ │ │ ├── HeaderProfile.jsx
│ │ │ ├── HeaderProfile.scss
│ │ │ ├── __tests__
│ │ │ │ ├── Header.spec.jsx
│ │ │ │ └── HeaderProfile.spec.jsx
│ │ │ ├── index.jsx
│ │ │ └── types.js
│ │ ├── Input
│ │ │ ├── Input.scss
│ │ │ ├── InputCheckbox.jsx
│ │ │ ├── InputCheckboxGroup.jsx
│ │ │ ├── InputDefault.jsx
│ │ │ ├── InputError.jsx
│ │ │ ├── InputLabel.jsx
│ │ │ ├── InputLocation.jsx
│ │ │ ├── InputMultiSelect.jsx
│ │ │ ├── InputMultiSelect.scss
│ │ │ ├── InputPassword.jsx
│ │ │ ├── InputPassword.scss
│ │ │ ├── InputRadioGroup.jsx
│ │ │ ├── InputRadioGroup.scss
│ │ │ ├── InputSelect.jsx
│ │ │ ├── InputSubmit.jsx
│ │ │ ├── InputSwitch.jsx
│ │ │ ├── InputSwitch.scss
│ │ │ ├── InputTag.jsx
│ │ │ ├── InputTag.scss
│ │ │ ├── InputTextarea.jsx
│ │ │ ├── InputTextarea.scss
│ │ │ ├── InputTextareaTemplate.jsx
│ │ │ ├── __tests__
│ │ │ │ ├── Input.spec.jsx
│ │ │ │ ├── InputCheckbox.spec.jsx
│ │ │ │ ├── InputCheckboxGroup.spec.jsx
│ │ │ │ ├── InputDefault.spec.jsx
│ │ │ │ ├── InputError.spec.jsx
│ │ │ │ ├── InputLabel.spec.jsx
│ │ │ │ ├── InputLocation.spec.jsx
│ │ │ │ ├── InputMultiSelect.spec.jsx
│ │ │ │ ├── InputPassword.spec.jsx
│ │ │ │ ├── InputRadioGroup.spec.jsx
│ │ │ │ ├── InputSelect.spec.jsx
│ │ │ │ ├── InputSubmit.spec.jsx
│ │ │ │ ├── InputSwitch.spec.jsx
│ │ │ │ ├── InputTag.spec.jsx
│ │ │ │ ├── InputTextarea.spec.jsx
│ │ │ │ └── InputTextareaTemplate.spec.jsx
│ │ │ ├── index.jsx
│ │ │ └── utils.js
│ │ ├── LoadMoreButton
│ │ │ ├── LoadMoreButton.scss
│ │ │ ├── __tests__
│ │ │ │ └── LoadMoreButton.spec.jsx
│ │ │ └── index.jsx
│ │ ├── Logo
│ │ │ ├── Logo.scss
│ │ │ ├── LogoFactory.jsx
│ │ │ ├── __tests__
│ │ │ │ └── Logo.spec.jsx
│ │ │ └── index.js
│ │ ├── Modal
│ │ │ ├── Modal.scss
│ │ │ ├── __tests__
│ │ │ │ └── Modal.spec.jsx
│ │ │ └── index.jsx
│ │ ├── OAuthButton
│ │ │ ├── OAuthButton.scss
│ │ │ ├── __tests__
│ │ │ │ └── OAuthButton.spec.jsx
│ │ │ ├── facebookIcon.svg
│ │ │ ├── googleIcon.svg
│ │ │ └── index.jsx
│ │ ├── PageTitle
│ │ │ ├── __tests__
│ │ │ │ └── PageTitle.spec.jsx
│ │ │ └── index.jsx
│ │ ├── Resource
│ │ │ ├── Resource.scss
│ │ │ ├── __tests__
│ │ │ │ └── Resource.spec.jsx
│ │ │ └── index.jsx
│ │ ├── SkipToContent
│ │ │ ├── SkipToContent.scss
│ │ │ ├── __tests__
│ │ │ │ └── SkipToContent.spec.jsx
│ │ │ └── index.jsx
│ │ ├── Story
│ │ │ ├── Story.scss
│ │ │ ├── StoryActions.jsx
│ │ │ ├── StoryBy.jsx
│ │ │ ├── StoryCategories.jsx
│ │ │ ├── StoryDate.jsx
│ │ │ ├── StoryDraft.jsx
│ │ │ ├── StoryMedication.jsx
│ │ │ ├── StoryMoods.jsx
│ │ │ ├── StoryName.jsx
│ │ │ ├── __tests__
│ │ │ │ ├── Story.spec.jsx
│ │ │ │ ├── StoryActions.spec.jsx
│ │ │ │ ├── StoryBy.spec.jsx
│ │ │ │ ├── StoryCategories.spec.jsx
│ │ │ │ ├── StoryDate.spec.jsx
│ │ │ │ ├── StoryDraft.spec.jsx
│ │ │ │ ├── StoryMedication.spec.jsx
│ │ │ │ ├── StoryMoods.spec.jsx
│ │ │ │ └── StoryName.spec.jsx
│ │ │ └── index.jsx
│ │ ├── Tag
│ │ │ ├── Tag.scss
│ │ │ ├── __tests__
│ │ │ │ └── Tag.spec.jsx
│ │ │ └── index.jsx
│ │ ├── Toast
│ │ │ ├── Toast.scss
│ │ │ ├── __tests__
│ │ │ │ └── Toast.spec.jsx
│ │ │ └── index.jsx
│ │ └── Tooltip
│ │ │ ├── Tooltip.scss
│ │ │ ├── __tests__
│ │ │ └── Tooltip.spec.jsx
│ │ │ └── index.jsx
│ ├── hooks
│ │ ├── index.js
│ │ └── useFocusTrap.js
│ ├── libs
│ │ ├── history.js
│ │ ├── i18n
│ │ │ ├── __tests__
│ │ │ │ └── i18n.spec.js
│ │ │ └── index.js
│ │ └── testHelper.js
│ ├── mocks
│ │ └── InputMocks.jsx
│ ├── pages
│ │ └── MomentTemplates
│ │ │ ├── MomentTemplate.jsx
│ │ │ ├── MomentTemplates.scss
│ │ │ ├── MomentTemplatesContext.jsx
│ │ │ ├── MomentTemplatesForm.jsx
│ │ │ ├── __tests__
│ │ │ └── MomentTemplates.spec.jsx
│ │ │ └── index.jsx
│ ├── startup
│ │ ├── registration.js
│ │ ├── scrollToTop.js
│ │ └── setTimezone.js
│ ├── stories
│ │ ├── .eslintrc
│ │ ├── Accordion.stories.jsx
│ │ ├── Avatar.stories.jsx
│ │ ├── Blockquote.stories.jsx
│ │ ├── Buttons.stories.jsx
│ │ ├── Chart.stories.jsx
│ │ ├── Colors.stories.jsx
│ │ ├── Errors.stories.jsx
│ │ ├── Fonts.stories.jsx
│ │ ├── Form.stories.jsx
│ │ ├── Grids.stories.jsx
│ │ ├── Header.stories.jsx
│ │ ├── I18n.stories.jsx
│ │ ├── Index.stories.jsx
│ │ ├── Input.stories.jsx
│ │ ├── Logo.stories.jsx
│ │ ├── Margins.stories.jsx
│ │ ├── Modal.stories.jsx
│ │ ├── OAuthButton.stories.jsx
│ │ ├── PageTitle.stories.jsx
│ │ ├── Resource.stories.jsx
│ │ ├── Story.stories.jsx
│ │ ├── Tag.stories.jsx
│ │ ├── Toast.stories.jsx
│ │ └── Tooltip.stories.jsx
│ ├── styles
│ │ ├── _global.scss
│ │ ├── _global_font.scss
│ │ └── _legacy.scss
│ ├── utils
│ │ ├── __tests__
│ │ │ └── index.spec.jsx
│ │ └── index.js
│ └── widgets
│ │ ├── CarePlanContacts
│ │ ├── CarePlanContacts.scss
│ │ ├── CarePlanContactsContext.jsx
│ │ ├── CarePlanContactsForm.jsx
│ │ ├── __tests__
│ │ │ └── index.spec.jsx
│ │ └── index.jsx
│ │ ├── Comments
│ │ ├── Comments.scss
│ │ ├── __tests__
│ │ │ └── Comments.spec.jsx
│ │ └── index.jsx
│ │ ├── CrisisPrevention
│ │ ├── CrisisPrevention.scss
│ │ ├── __tests___
│ │ │ └── index.spec.jsx
│ │ └── index.jsx
│ │ ├── Notifications
│ │ ├── __tests__
│ │ │ └── Notifications.spec.jsx
│ │ └── index.jsx
│ │ ├── QuickCreate
│ │ ├── QuickCreate.scss
│ │ ├── __tests__
│ │ │ └── QuickCreate.spec.jsx
│ │ └── index.jsx
│ │ ├── Resources
│ │ ├── Resources.scss
│ │ ├── __tests__
│ │ │ └── Resources.spec.jsx
│ │ └── index.jsx
│ │ └── ToggleLocale
│ │ ├── __tests__
│ │ └── ToggleLocale.spec.jsx
│ │ └── index.jsx
├── flow
│ ├── media.js
│ └── stylesheets.js
├── jest
│ └── svgTransform.js
├── package.json
├── webpack.config.js
└── yarn.lock
├── code_of_conduct.md
├── config.ru
├── config
├── .yamllint
├── application.rb
├── boot.rb
├── cable.yml
├── cloudinary.yml
├── content_security_policy.rb
├── database.yml
├── env
│ ├── development.example.env
│ └── test.example.env
├── environment.rb
├── environments
│ ├── development.rb
│ ├── production.rb
│ └── test.rb
├── initializers
│ ├── application_controller_renderer.rb
│ ├── assets.rb
│ ├── backtrace_silencers.rb
│ ├── bullet.rb
│ ├── carrierwave.rb
│ ├── cloudinary.rb
│ ├── content_security_policy.rb
│ ├── cookies_serializer.rb
│ ├── devise.rb
│ ├── filter_parameter_logging.rb
│ ├── friendly_id.rb
│ ├── inflections.rb
│ ├── kaminari_config.rb
│ ├── mime_types.rb
│ ├── new_framework_defaults.rb
│ ├── new_framework_defaults_6_0.rb
│ ├── new_framework_defaults_7_0.rb
│ ├── permissions_policy.rb
│ ├── premailer_rails.rb
│ ├── pusher.rb
│ ├── react_on_rails.rb
│ ├── recaptcha.rb
│ ├── session_store.rb
│ ├── sidekiq.rb
│ ├── timeout.rb
│ └── wrap_parameters.rb
├── locale.rb
├── locales
│ ├── de.yml
│ ├── devise.de.yml
│ ├── devise.en.yml
│ ├── devise.es.yml
│ ├── devise.fr.yml
│ ├── devise.hi.yml
│ ├── devise.id.yml
│ ├── devise.it.yml
│ ├── devise.ko.yml
│ ├── devise.nb.yml
│ ├── devise.nl.yml
│ ├── devise.pt-BR.yml
│ ├── devise.sv.yml
│ ├── devise.vi.yml
│ ├── devise.zh-CN.yml
│ ├── devise_invitable.de.yml
│ ├── devise_invitable.en.yml
│ ├── devise_invitable.es.yml
│ ├── devise_invitable.fr.yml
│ ├── devise_invitable.hi.yml
│ ├── devise_invitable.id.yml
│ ├── devise_invitable.it.yml
│ ├── devise_invitable.ko.yml
│ ├── devise_invitable.nb.yml
│ ├── devise_invitable.nl.yml
│ ├── devise_invitable.pt-BR.yml
│ ├── devise_invitable.sv.yml
│ ├── devise_invitable.vi.yml
│ ├── devise_invitable.zh-CN.yml
│ ├── en.yml
│ ├── es.yml
│ ├── fr.yml
│ ├── hi.yml
│ ├── id.yml
│ ├── it.yml
│ ├── ko.yml
│ ├── nb.yml
│ ├── nl.yml
│ ├── pt-BR.yml
│ ├── sv.yml
│ ├── vi.yml
│ └── zh-CN.yml
├── puma.rb
├── routes.rb
├── secrets.yml
├── sidekiq.yml
├── sidekiq_schedule.yml
├── spring.rb
├── storage.yml
└── webpacker.yml
├── db
├── migrate
│ ├── 20150506005730_setup_database.rb
│ ├── 20151205193444_add_relations.rb
│ ├── 20151205193712_change_column_names_in_allyships.rb
│ ├── 20160429191349_create_notifications.rb
│ ├── 20160506154041_devise_invitable_add_to_users.rb
│ ├── 20160511231156_add_viewers_to_comments.rb
│ ├── 20160512174202_set_limits_on_text.rb
│ ├── 20160516202831_add_notifications_to_users.rb
│ ├── 20160518220139_create_medication_reminders.rb
│ ├── 20161127002019_create_strategy_reminders.rb
│ ├── 20161127232311_create_friendly_id_slugs.rb
│ ├── 20161127233144_add_slug_to_moments.rb
│ ├── 20161215060504_add_slug_to_models.rb
│ ├── 20170225182017_add_locale_to_users.rb
│ ├── 20170724124951_add_access_expires_at_to_user.rb
│ ├── 20170724160338_add_refresh_token_to_user.rb
│ ├── 20170724205314_add_secret_shares_to_moments.rb
│ ├── 20170806232047_change_column_names_in_moments.rb
│ ├── 20170825205513_change_comments_to_be_polymorphic.rb
│ ├── 20170830075513_add_add_to_google_cal_to_medication.rb
│ ├── 20171006164206_add_published_at_field_to_moments.rb
│ ├── 20171006164223_add_published_at_field_to_strategies.rb
│ ├── 20171010054721_set_default_publication_date.rb
│ ├── 20180213160537_add_weekly_dosage_to_medication.rb
│ ├── 20180318075504_rename_userid_on_categories.rb
│ ├── 20180318080518_rename_groupid_on_group_members.rb
│ ├── 20180405152328_rename_userid_on_moods.rb
│ ├── 20180405153007_rename_userid_on_strategies.rb
│ ├── 20180406232114_rename_userid_on_moments.rb
│ ├── 20180716033741_rename_userid_on_meetings.rb
│ ├── 20180716035719_rename_userid_on_notifications.rb
│ ├── 20180716035735_rename_userid_on_supports.rb
│ ├── 20180716035805_rename_userid_on_medications.rb
│ ├── 20180716035824_rename_userid_on_meeting_members.rb
│ ├── 20180716040119_rename_userid_on_group_members.rb
│ ├── 20180724031319_rename_meetingid_on_meeting_members.rb
│ ├── 20180908064825_add_banned_to_users.rb
│ ├── 20181030143627_create_password_histories.rb
│ ├── 20181103000528_add_reports.rb
│ ├── 20181103000904_add_admin_to_users.rb
│ ├── 20181119152925_change_refill_column_type.rb
│ ├── 20190316160238_add_google_cal_event_id_to_meeting_members.rb
│ ├── 20190419023259_replace_empty_name_with_email.rb
│ ├── 20190821013432_add_third_party_avatar_to_user.rb
│ ├── 20200201005100_add_visible_to_categories.rb
│ ├── 20200201005117_add_visible_to_strategies.rb
│ ├── 20200208223501_add_visible_to_moods.rb
│ ├── 20200219155053_create_moment_moods_join_table.rb
│ ├── 20200221153634_drop_moments_mood_column.rb
│ ├── 20200224201131_create_moment_categories_join_table.rb
│ ├── 20200224205313_drop_moments_category_column.rb
│ ├── 20200224231844_create_moment_strategies_join_table.rb
│ ├── 20200224234822_drop_moments_strategy_column.rb
│ ├── 20200225003308_create_strategy_categories_join_table.rb
│ ├── 20200225010346_drop_strategies_category_column.rb
│ ├── 20200419063429_add_bookmarked_to_moments.rb
│ ├── 20200419063936_add_bookmarked_to_strategies.rb
│ ├── 20200506222107_add_resource_recommendations_to_moments.rb
│ ├── 20200509110917_add_foreign_key_constraint_to_active_storage_attachments_for_blob_id.active_storage.rb
│ ├── 20200513052758_add_user_id_index_to_password_histories.rb
│ ├── 20200527035711_create_care_plan_contacts.rb
│ ├── 20201008170831_create_users_data_requests.rb
│ ├── 20201009185200_drop_password_histories_table.rb
│ ├── 20201019231628_add_lockable_attributes_to_user.rb
│ ├── 20210328174852_create_moment_templates.rb
│ ├── 20211005010735_add_confirmable_to_devise.rb
│ ├── 20220204015546_add_session_token_to_users.rb
│ ├── 20221025214531_add_service_name_to_active_storage_blobs.active_storage.rb
│ ├── 20221025214532_create_active_storage_variant_records.active_storage.rb
│ └── 20221025214533_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb
├── schema.rb
└── seeds.rb
├── doc
├── controllers_brief.svg
├── controllers_complete.svg
├── erd.pdf
├── models_brief.svg
├── models_complete.svg
└── pages
│ ├── blurbs.json
│ ├── contributors.json
│ ├── partners.json
│ ├── press.json
│ └── resources.json
├── docker-compose.test.yml
├── docker-compose.yml
├── docker-entrypoint.sh
├── git-hooks
├── pre-commit
└── pre-push
├── lib
├── access_token.rb
├── tasks
│ ├── cleaner.rake
│ ├── scheduler.rake
│ └── slugs.rake
└── url_helper.rb
├── package.json
├── public
├── 422.html
├── favicon.ico
├── logo@2x.png
├── logo_512.png
├── manifest.json
├── robots.txt
└── wiki_images
│ ├── macos-installation-map.png
│ ├── new-accounts-settings.png
│ ├── new-allies-page.png
│ ├── new-categories-page.png
│ ├── new-groups-page.png
│ ├── new-landing-page.png
│ ├── new-medications-form.png
│ ├── new-medications-page.png
│ ├── new-moments-page.png
│ ├── new-moods-page.png
│ └── new-strategies-page.png
├── spec
├── compare_locales_support_spec.rb
├── concerns
│ ├── ally_concern_spec.rb
│ ├── collection_page_setup_concern_spec.rb
│ ├── page_redirect_concern_spec.rb
│ └── shared_basic_concern_spec.rb
├── factories
│ ├── care_plan_contacts.rb
│ ├── category.rb
│ ├── factories.rb
│ ├── moment.rb
│ ├── moment_templates.rb
│ ├── mood.rb
│ ├── notification.rb
│ ├── strategy.rb
│ ├── support.rb
│ ├── user.rb
│ └── users
│ │ └── data_requests.rb
├── features
│ ├── leader_edits_groups_spec.rb
│ ├── persisting_browser_locale_after_sign_in_spec.rb
│ ├── resources_load_more_spec.rb
│ ├── toggle_locale_spec.rb
│ ├── user_auth_spec.rb
│ ├── user_creates_a_care_plan_contact_spec.rb
│ ├── user_creates_a_draft_moment_spec.rb
│ ├── user_creates_a_draft_strategy_spec.rb
│ ├── user_creates_a_medication_spec.rb
│ ├── user_creates_a_moment_template_spec.rb
│ ├── user_creates_a_published_moment_spec.rb
│ ├── user_creates_a_published_strategy_spec.rb
│ ├── user_creates_groups_spec.rb
│ ├── user_deletes_a_care_plan_contact_spec.rb
│ ├── user_deletes_a_moment_template_spec.rb
│ ├── user_displays_resources_links_spec.rb
│ ├── user_leaves_groups_spec.rb
│ ├── user_updates_a_care_plan_contact_spec.rb
│ ├── user_updates_a_moment_templates_spec.rb
│ ├── user_updates_groups_spec.rb
│ ├── user_updates_profile_spec.rb
│ ├── user_visits_group_show_spec.rb
│ └── user_visits_groups_pages_spec.rb
├── helpers
│ ├── access_token_spec.rb
│ ├── application_helper_spec.rb
│ ├── assets_helper_spec.rb
│ ├── calendar_helper_spec.rb
│ ├── categories_helper_spec.rb
│ ├── comments_form_helper_spec.rb
│ ├── comments_helper_spec.rb
│ ├── dashboard_nav_helper_spec.rb
│ ├── date_time_helper_spec.rb
│ ├── form_helper_spec.rb
│ ├── groups
│ │ ├── form_helper_spec.rb
│ │ └── memberships_helper_spec.rb
│ ├── groups_form_helper_spec.rb
│ ├── groups_helper_spec.rb
│ ├── header_helper_spec.rb
│ ├── medication_refill_helper_spec.rb
│ ├── medications_form_helper_spec.rb
│ ├── medications_helper_spec.rb
│ ├── meetings_form_helper_spec.rb
│ ├── meetings_helper_spec.rb
│ ├── moments_form_helper_spec.rb
│ ├── moments_helper_spec.rb
│ ├── moments_stats_helper_spec.rb
│ ├── moods_helper_spec.rb
│ ├── most_focus_helper_spec.rb
│ ├── notifications_helper_spec.rb
│ ├── pages_helper_spec.rb
│ ├── reminder_helper_spec.rb
│ ├── reports_helper_spec.rb
│ ├── shared_examples.rb
│ ├── stories_helper_spec.rb
│ ├── strategies_form_helper.spec.rb
│ ├── strategies_helper_spec.rb
│ ├── tags_helper_spec.rb
│ ├── viewers_helper_spec.rb
│ └── visible_helper_spec.rb
├── mailers
│ ├── ally_notifications
│ │ ├── accepted_ally_request_spec.rb
│ │ └── new_ally_request_spec.rb
│ ├── application_mailer_spec.rb
│ ├── banned_mailer_spec.rb
│ ├── custom_devise_mailer_spec.rb
│ ├── notification_mailer_spec.rb
│ ├── previews
│ │ └── notification_mailer_preview.rb
│ └── report_mailer_spec.rb
├── models
│ ├── allyship_spec.rb
│ ├── care_plan_contact_spec.rb
│ ├── category_spec.rb
│ ├── comment_spec.rb
│ ├── group_member_spec.rb
│ ├── group_notifier_spec.rb
│ ├── group_spec.rb
│ ├── medication_spec.rb
│ ├── meeting_member_spec.rb
│ ├── meeting_spec.rb
│ ├── moment_spec.rb
│ ├── moment_template_spec.rb
│ ├── mood_spec.rb
│ ├── notification_spec.rb
│ ├── perform_strategy_reminder_spec.rb
│ ├── refill_reminder_spec.rb
│ ├── report_spec.rb
│ ├── strategy_spec.rb
│ ├── support_spec.rb
│ ├── take_medication_reminder_spec.rb
│ ├── user_spec.rb
│ └── users
│ │ └── data_request_spec.rb
├── requests
│ ├── allies_spec.rb
│ ├── care_plan_contacts_spec.rb
│ ├── care_plan_spec.rb
│ ├── categories_spec.rb
│ ├── comments_spec.rb
│ ├── errors_spec.rb
│ ├── groups
│ │ └── membership_spec.rb
│ ├── groups_spec.rb
│ ├── locales_spec.rb
│ ├── medications_spec.rb
│ ├── meetings
│ │ └── google_calendar_event_spec.rb
│ ├── meetings_spec.rb
│ ├── moment_templates_spec.rb
│ ├── moments_spec.rb
│ ├── moods_spec.rb
│ ├── notifications_spec.rb
│ ├── omniauth_callbacks_spec.rb
│ ├── pages_spec.rb
│ ├── profile_spec.rb
│ ├── pusher_spec.rb
│ ├── registrations_spec.rb
│ ├── reports_spec.rb
│ ├── search_spec.rb
│ ├── secret_shares_spec.rb
│ ├── sessions_spec.rb
│ ├── strategies_spec.rb
│ └── users
│ │ ├── invitation_spec.rb
│ │ └── reports_request_spec.rb
├── routing
│ └── locale_routing_spec.rb
├── services
│ ├── allyship_creator_spec.rb
│ ├── allyships
│ │ └── alliance_notifier_spec.rb
│ ├── calendar_uploader_spec.rb
│ ├── cloudinary_service_spec.rb
│ ├── comment_notifications_service_spec.rb
│ ├── comment_viewers_service_spec.rb
│ ├── group_notifier_spec.rb
│ ├── leader_updater_spec.rb
│ ├── medication_reminders_spec.rb
│ ├── medium_spec.rb
│ ├── meeting_notifications_service_spec.rb
│ ├── meeting_reminders_spec.rb
│ ├── moment_keywords_spec.rb
│ ├── profile_picture_spec.rb
│ ├── recaptcha_service_spec.rb
│ ├── resource_recommendations_spec.rb
│ ├── strategy_reminders_spec.rb
│ └── time_ago_spec.rb
├── spec_helper.rb
├── support
│ ├── compare_locales_support.rb
│ ├── database_cleaner.rb
│ ├── hidden_header_support.rb
│ ├── page_transition_support.rb
│ ├── scroll_spec_support.rb
│ ├── shared_contexts
│ │ └── logged_in_user.rb
│ ├── shared_examples
│ │ └── with_no_logged_in_user.rb
│ ├── stub_current_user.rb
│ ├── stub_omniauth.rb
│ └── textarea_support.rb
└── uploads
│ └── moment.jpeg
└── yarn.lock
/.codeclimate.yml:
--------------------------------------------------------------------------------
1 | version: "2"
2 |
3 | plugins:
4 | brakeman:
5 | enabled: true
6 | bundler-audit:
7 | enabled: true
8 | csslint:
9 | enabled: true
10 | duplication:
11 | enabled: true
12 | config:
13 | languages:
14 | ruby: {}
15 | javascript:
16 | mass_threshold: 80
17 | exclude_paths:
18 | - "client/**/__tests__/"
19 | eslint:
20 | enabled: true
21 | channel: "eslint-7"
22 | exclude_paths:
23 | - public/javascripts/
24 | - vendor/assets/javascripts
25 | - client/flow/
26 | fixme:
27 | enabled: false
28 | rubocop:
29 | enabled: true
30 | channel: rubocop-1-56-3
31 | ratings:
32 | paths:
33 | - Gemfile.lock
34 | - "**.erb"
35 | - "**.rb"
36 | - "**.css"
37 | - "**.js"
38 | exclude_paths:
39 | - config/
40 | - db/
41 | - spec/
42 |
--------------------------------------------------------------------------------
/.csslintrc:
--------------------------------------------------------------------------------
1 | --exclude-exts=.min.css
2 | --ignore=adjoining-classes,box-model,ids,order-alphabetical,unqualified-attributes
3 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | # git files
2 | .git
3 | .gitignore
4 | .gitkeep
5 | .keep
6 | git-hooks
7 |
8 | # logfiles and tempfiles
9 | coverage
10 | tmp
11 | log
12 | **/*.log
13 | **/npm-debug.log*
14 |
15 | # OS files
16 | **/*.DS_Store
17 | **/Thumbs.db
18 |
19 | # IDE & editor configuration
20 | .vs*
21 | .idea
22 | .tags
23 | **/*.swp
24 |
25 | # managed dependencies
26 | **/node_modules
27 | **/v8-compile-cache-*/
28 |
29 | # generated JavaScript
30 | public/javascripts
31 | public/webpack
32 | public/webpack-test
33 |
34 | # documentation for project contributors
35 | *.md
36 |
37 | # configuration that doesn't need to be in the image
38 | .circleci
39 | .codeclimate.yml
40 | .dockerignore
41 | .github
42 | Dockerfile
43 | docker-compose.yml
44 | docker-compose.*.yml
45 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*.rb]
4 | indent_style = space
5 | indent_size = 2
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
13 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | **/*{.,-}min.js
2 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | @ifmeorg/rgsoc-mentors
2 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | 20.17.0
--------------------------------------------------------------------------------
/.rspec:
--------------------------------------------------------------------------------
1 | --color
2 | --require spec_helper
3 |
--------------------------------------------------------------------------------
/.ruby-gemset:
--------------------------------------------------------------------------------
1 | ifme
2 |
--------------------------------------------------------------------------------
/.ruby-version:
--------------------------------------------------------------------------------
1 | 3.1.4
2 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "javascript.validate.enable": false
3 | }
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | # Procfile
2 | web: bundle exec puma -C config/puma.rb
--------------------------------------------------------------------------------
/Procfile.dev:
--------------------------------------------------------------------------------
1 | web: bash -c "rm -rf ./tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
2 | client: sh -c 'bin/client.sh'
3 |
--------------------------------------------------------------------------------
/app/assets/images/contributors/Arun_Kumar.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/Arun_Kumar.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/Ghada_AbdulWahab.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/Ghada_AbdulWahab.png
--------------------------------------------------------------------------------
/app/assets/images/contributors/Hassan_Ahmed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/Hassan_Ahmed.png
--------------------------------------------------------------------------------
/app/assets/images/contributors/Krishanu_Shashwat.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/Krishanu_Shashwat.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/Oliver_Ikegah.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/Oliver_Ikegah.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/Olivia_Robinson.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/Olivia_Robinson.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/Sourabh_Yadav.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/Sourabh_Yadav.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/Zeeshan_Sarwar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/Zeeshan_Sarwar.png
--------------------------------------------------------------------------------
/app/assets/images/contributors/abe_dolinger.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/abe_dolinger.jpeg
--------------------------------------------------------------------------------
/app/assets/images/contributors/adan_amarillas.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/adan_amarillas.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/alex_fa.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/alex_fa.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/alex_manzo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/alex_manzo.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/alline_marjorie.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/alline_marjorie.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/angel_quesada.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/angel_quesada.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/atibhi_agrawal.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/atibhi_agrawal.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/bee_martinez.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/bee_martinez.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/ben_pham.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/ben_pham.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/britton_jenner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/britton_jenner.png
--------------------------------------------------------------------------------
/app/assets/images/contributors/camila_campos.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/camila_campos.png
--------------------------------------------------------------------------------
/app/assets/images/contributors/carl_summers.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/carl_summers.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/chibuzor_efedigbue.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/chibuzor_efedigbue.jpeg
--------------------------------------------------------------------------------
/app/assets/images/contributors/claire_wild.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/claire_wild.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/daaimah_tibrey.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/daaimah_tibrey.png
--------------------------------------------------------------------------------
/app/assets/images/contributors/darryl_dixon.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/darryl_dixon.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/dena_burd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/dena_burd.png
--------------------------------------------------------------------------------
/app/assets/images/contributors/desi_rottman.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/desi_rottman.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/ellen_macpherson.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/ellen_macpherson.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/emma_smith.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/emma_smith.png
--------------------------------------------------------------------------------
/app/assets/images/contributors/francisco_perejon.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/francisco_perejon.jpeg
--------------------------------------------------------------------------------
/app/assets/images/contributors/george_karametas.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/george_karametas.png
--------------------------------------------------------------------------------
/app/assets/images/contributors/gurpreet_gill.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/gurpreet_gill.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/haley_mnatzaganian.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/haley_mnatzaganian.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/hnarasaki.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/hnarasaki.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/ingrid_garcia.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/ingrid_garcia.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/irene_li.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/irene_li.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/irmak_aytekin.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/irmak_aytekin.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/isabelle_yiu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/isabelle_yiu.png
--------------------------------------------------------------------------------
/app/assets/images/contributors/jasmine_logan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/jasmine_logan.png
--------------------------------------------------------------------------------
/app/assets/images/contributors/jason_alsip.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/jason_alsip.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/jasper_martin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/jasper_martin.png
--------------------------------------------------------------------------------
/app/assets/images/contributors/jennifer_parsons.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/jennifer_parsons.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/jennifer_shen.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/jennifer_shen.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/jennifer_winer.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/jennifer_winer.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/jenny_nam.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/jenny_nam.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/jenny_nguyen.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/jenny_nguyen.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/jeremiah_tabb.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/jeremiah_tabb.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/john_maguire.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/john_maguire.png
--------------------------------------------------------------------------------
/app/assets/images/contributors/jon_tan.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/jon_tan.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/julia_nguyen.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/julia_nguyen.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/julian_macmang.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/julian_macmang.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/karolina_benitez.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/karolina_benitez.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/kelly_sousa.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/kelly_sousa.png
--------------------------------------------------------------------------------
/app/assets/images/contributors/lee_mulvey.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/lee_mulvey.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/liliana_velazquez.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/liliana_velazquez.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/lisette_ruiz.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/lisette_ruiz.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/lucy_yu.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/lucy_yu.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/manish_sharma.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/manish_sharma.jpeg
--------------------------------------------------------------------------------
/app/assets/images/contributors/manish_yadav.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/manish_yadav.jpeg
--------------------------------------------------------------------------------
/app/assets/images/contributors/maribel_duran.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/maribel_duran.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/miguel_navarrete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/miguel_navarrete.png
--------------------------------------------------------------------------------
/app/assets/images/contributors/mohammad_aakash.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/mohammad_aakash.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/muhammad_rahmatullah.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/muhammad_rahmatullah.jpeg
--------------------------------------------------------------------------------
/app/assets/images/contributors/nagma_kapoor.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/nagma_kapoor.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/nicholas_lee.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/nicholas_lee.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/nikhil_bhatt.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/nikhil_bhatt.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/nishiki_liu.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/nishiki_liu.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/pedro_paulino.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/pedro_paulino.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/pierre_monier.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/pierre_monier.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/prateksha_udhayanan.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/prateksha_udhayanan.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/rebecca_taylor.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/rebecca_taylor.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/rizka_luthfiani.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/rizka_luthfiani.jpeg
--------------------------------------------------------------------------------
/app/assets/images/contributors/seun_adekunle.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/seun_adekunle.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/sonu_toor.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/sonu_toor.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/sophie_mcdonald.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/sophie_mcdonald.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/srishti_gupta.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/srishti_gupta.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/stephanie_warmenhoven.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/stephanie_warmenhoven.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/tara_swenson.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/tara_swenson.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/tara_wilkins.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/tara_wilkins.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/ted_vu.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/ted_vu.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/tracy_holmes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/tracy_holmes.png
--------------------------------------------------------------------------------
/app/assets/images/contributors/tyler_walker.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/tyler_walker.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/tyler_welsh.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/tyler_welsh.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/udayan_shevade.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/udayan_shevade.png
--------------------------------------------------------------------------------
/app/assets/images/contributors/valeria_kolisnyk.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/valeria_kolisnyk.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/varshini_ananta.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/varshini_ananta.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/vilde_vevatne.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/vilde_vevatne.jpg
--------------------------------------------------------------------------------
/app/assets/images/contributors/yuri.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/contributors/yuri.jpg
--------------------------------------------------------------------------------
/app/assets/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/favicon.ico
--------------------------------------------------------------------------------
/app/assets/images/partners/brown_sisters_speak.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/partners/brown_sisters_speak.png
--------------------------------------------------------------------------------
/app/assets/images/partners/dpga.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/partners/dpga.png
--------------------------------------------------------------------------------
/app/assets/images/partners/everybody_has_a_brain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/partners/everybody_has_a_brain.png
--------------------------------------------------------------------------------
/app/assets/images/partners/hacker_hours.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/partners/hacker_hours.png
--------------------------------------------------------------------------------
/app/assets/images/partners/mh_prompt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/partners/mh_prompt.png
--------------------------------------------------------------------------------
/app/assets/images/partners/osmi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/partners/osmi.png
--------------------------------------------------------------------------------
/app/assets/images/partners/rails_girls_summer_of_code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/partners/rails_girls_summer_of_code.png
--------------------------------------------------------------------------------
/app/assets/images/partners/seadc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/partners/seadc.png
--------------------------------------------------------------------------------
/app/assets/images/partners/write_speak_code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ifmeorg/ifme/28e4fe5001cdabcc46972a6c96a6c7fbf461fe0f/app/assets/images/partners/write_speak_code.png
--------------------------------------------------------------------------------
/app/assets/javascripts/application.js:
--------------------------------------------------------------------------------
1 | // This is a manifest file that'll be compiled into application.js, which will include all the files
2 | // listed below.
3 | //
4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5 | // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6 | //
7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8 | // compiled file.
9 | //
10 | // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
11 | // about supported directives.
12 | //
13 | //= require jquery
14 | //= require jquery_ujs
15 | //= require turbolinks
16 | //= require_tree .
17 |
--------------------------------------------------------------------------------
/app/assets/javascripts/require_recaptcha.js:
--------------------------------------------------------------------------------
1 | function recaptcha_verified () {
2 | document.querySelector('.recaptcha_submit').removeAttribute('disabled')
3 | }
4 |
5 | function recaptcha_expired () {
6 | document.querySelector('.recaptcha_submit').setAttribute('disabled', 'disabled')
7 | }
8 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/application/allies.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the Allies controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
5 | /* Allies */
6 |
7 | .ally {
8 | text-align: center;
9 |
10 | a {
11 | @include standardTransition();
12 | }
13 |
14 | > a:first-of-type {
15 | @include setMargin($size-0, $size-0, $size-20, $size-0);
16 |
17 | display: block;
18 | color: $mulberry;
19 | font-weight: bold;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/application/profile.scss:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the Profile controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
5 | /* Profiles */
6 |
7 | .profile {
8 | display: flex;
9 | flex-direction: row;
10 | align-items: center;
11 |
12 | &Info {
13 | margin-left: $size-20;
14 |
15 | > div {
16 | @include setMargin($size-0, $size-0, $size-10, $size-0);
17 | }
18 |
19 | > div:last-of-type {
20 | margin: $size-0;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/base/_animations.scss:
--------------------------------------------------------------------------------
1 | @mixin fadeIn($duration) {
2 | -webkit-animation-duration: $duration;
3 | animation-duration: $duration;
4 | -webkit-animation-fill-mode: both;
5 | animation-fill-mode: both;
6 | -webkit-animation-name: fadein;
7 | animation-name: fadeIn;
8 |
9 | @-webkit-keyframes fadeIn {
10 | 0% { opacity: 0; }
11 | 100% { opacity: 1; }
12 | }
13 |
14 | @keyframes fadeIn {
15 | 0% { opacity: 0; }
16 | 100% { opacity: 1; }
17 | }
18 | }
19 |
20 | @mixin linearTransition($duration) {
21 | transition: $duration;
22 | transition-timing-function: linear;
23 | }
24 |
25 | @mixin standardTransition() {
26 | transition: all 0.2s ease-in-out;
27 | }
28 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/base/_breakpoints.scss:
--------------------------------------------------------------------------------
1 | $x-small: 480px;
2 | $small: 640px;
3 | $medium: 1024px;
4 | $large: 1440px;
5 | $x-large: 1920px;
6 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/base/_fonts.scss:
--------------------------------------------------------------------------------
1 | @mixin setFontSize($font-size) {
2 | font-size: $font-size;
3 |
4 | @media screen and (max-width: $medium) {
5 | font-size: $font-size - $size-2;
6 | }
7 | }
8 |
9 | $font-family: 'Lato', sans-serif;
10 |
11 | $font-weight-100: 100;
12 | $font-weight-200: 200;
13 | $font-weight-300: 300;
14 | $font-weight-400: 400;
15 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/base/_margin.scss:
--------------------------------------------------------------------------------
1 | @mixin setMargin($top, $right, $bottom, $left) {
2 | margin: $top $right $bottom $left;
3 |
4 | @media screen and (max-width: $medium) {
5 | $newTop: if($top == 'auto', $top, calc($top / 2));
6 | $newRight: if($right == 'auto', $right, calc($right / 2));
7 | $newBottom: if($bottom == 'auto', $bottom, calc($bottom / 2));
8 | $newLeft: if($left == 'auto', $left, calc($left / 2));
9 |
10 | margin: $newTop $newRight $newBottom $newLeft;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/base/_padding.scss:
--------------------------------------------------------------------------------
1 | @mixin setPadding($top, $right, $bottom, $left) {
2 | padding: $top $right $bottom $left;
3 |
4 | @media screen and (max-width: $medium) {
5 | $newTop: if($top == 'auto', $top, calc($top / 2));
6 | $newRight: if($right == 'auto', $right, calc($right / 2));
7 | $newBottom: if($bottom == 'auto', $bottom, calc($bottom / 2));
8 | $newLeft: if($left == 'auto', $left, calc($left / 2));
9 |
10 | padding: $newTop $newRight $newBottom $newLeft;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/base/_sizes.scss:
--------------------------------------------------------------------------------
1 | $size-0: 0;
2 | $size-1: 1px;
3 | $size-2: 2px;
4 | $size-4: 4px;
5 | $size-6: 6px;
6 | $size-8: 8px;
7 | $size-10: 10px;
8 | $size-12: 12px;
9 | $size-14: 14px;
10 | $size-16: 16px;
11 | $size-18: 18px;
12 | $size-20: 20px;
13 | $size-22: 22px;
14 | $size-24: 24px;
15 | $size-26: 26px;
16 | $size-28: 28px;
17 | $size-30: 30px;
18 | $size-32: 32px;
19 | $size-34: 34px;
20 | $size-35: 35px;
21 | $size-36: 36px;
22 | $size-38: 38px;
23 | $size-40: 40px;
24 | $size-42: 42px;
25 | $size-44: 44px;
26 | $size-46: 46px;
27 | $size-48: 48px;
28 | $size-50: 50px;
29 | $size-60: 60px;
30 | $size-70: 70px;
31 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/base/_values.scss:
--------------------------------------------------------------------------------
1 | $z-index-front: 9000;
2 | $nav-height: 86px;
3 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/core/alerts.scss:
--------------------------------------------------------------------------------
1 | .alert {
2 | background: $carmine;
3 | color: $white;
4 | padding: $size-10;
5 | text-align: center;
6 | border-radius: $size-4;
7 |
8 | &Text {
9 | color: $carmine;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/core/containers.scss:
--------------------------------------------------------------------------------
1 | .center {
2 | text-align: center;
3 |
4 | &Margin {
5 | margin: 0 auto;
6 | }
7 | }
8 |
9 | .fullWidth {
10 | display: block;
11 | width: 100%;
12 | margin: 0;
13 | }
14 |
15 | .imageContainer {
16 | img {
17 | max-width: 100%;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/core/displays.scss:
--------------------------------------------------------------------------------
1 | .displayNone {
2 | display: none;
3 | }
4 |
5 | .hideOnMobile {
6 | @media screen and (max-width: $small) {
7 | display: none;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/core/forms.scss:
--------------------------------------------------------------------------------
1 | .label,
2 | label {
3 | @include setMargin($size-0, $size-0, $size-10, $size-0);
4 | @include setFontSize($size-16);
5 | @include linearTransition(0.25s);
6 |
7 | letter-spacing: 0.095em;
8 | text-transform: uppercase;
9 | font-weight: $font-weight-400;
10 | display: inherit;
11 | width: auto;
12 | }
13 |
14 | .label i,
15 | .sidebar_label i {
16 | opacity: 0.5;
17 | }
18 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/core/links.scss:
--------------------------------------------------------------------------------
1 | @mixin staticContentFakeLink() {
2 | @include standardTransition();
3 |
4 | text-decoration: none;
5 | color: $cornflower;
6 |
7 | &:hover,
8 | &:focus {
9 | opacity: 0.5;
10 | }
11 | }
12 |
13 | @mixin staticContentLink() {
14 | a {
15 | @include staticContentFakeLink();
16 | }
17 | }
18 |
19 | @mixin dashboardSectionFakeLink() {
20 | text-decoration: none;
21 | color: $blumine;
22 |
23 | &:hover,
24 | &:focus {
25 | opacity: 0.5;
26 | }
27 | }
28 |
29 | @mixin dashboardSectionLink() {
30 | a {
31 | @include dashboardSectionFakeLink();
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/core/notices.scss:
--------------------------------------------------------------------------------
1 | .notice {
2 | background: $limeade;
3 | color: $white;
4 | padding: $size-10;
5 | text-align: center;
6 | border-radius: $size-4;
7 | }
8 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/core/text.scss:
--------------------------------------------------------------------------------
1 | @mixin overflowText() {
2 | overflow: hidden;
3 | text-overflow: ellipsis;
4 | white-space: nowrap;
5 | }
6 |
7 | .subtle {
8 | color: $eggplant;
9 | }
10 |
11 | p {
12 | word-wrap: break-word;
13 | }
14 |
15 | .moment p {
16 | margin: 0;
17 | }
18 |
19 | .purpleYay {
20 | @include setFontSize($size-30);
21 |
22 | color: $purple-yay;
23 | text-shadow: $size-0 $size-0 $size-4 $purple-yay;
24 | }
25 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/dashboard/dashboard.scss:
--------------------------------------------------------------------------------
1 | .dashboard {
2 | background: $mulberry-key-lime;
3 | }
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/dashboard/dashboard_content.scss:
--------------------------------------------------------------------------------
1 | .dashboardContent {
2 | width: 100%;
3 | box-sizing: border-box;
4 | padding: $size-0 25px 50px 25px;
5 | display: flex;
6 | flex-direction: row;
7 | margin-top: $nav-height;
8 |
9 | @media screen and (max-width: $medium) {
10 | flex-direction: column;
11 | padding: 0;
12 | margin-top: 0;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/overrides/font_awesome.scss:
--------------------------------------------------------------------------------
1 | .fa-inline {
2 | @include setMargin($size-0, $size-10, $size-0, $size-0);
3 | }
4 |
5 | .fa-left {
6 | @include setMargin($size-0, $size-0, $size-0, $size-20);
7 | }
8 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/secret_share/secret_share_content.scss:
--------------------------------------------------------------------------------
1 | .secretShareContent {
2 | width: 100%;
3 | box-sizing: border-box;
4 | padding: 50px 25px;
5 | background: $white-80;
6 | margin-top: $nav-height;
7 |
8 | @media screen and (max-width: $medium) {
9 | margin-top: 0;
10 | }
11 |
12 | @include dashboardSectionStyles();
13 | }
14 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/static/static.scss:
--------------------------------------------------------------------------------
1 | .static {
2 | background-image: image-url('/assets/static_page_top_bg.svg'), image-url('/assets/static_page_bottom_bg.svg'), $mulberry-key-lime;
3 | background-size: 100% auto;
4 | background-position: center top, center bottom;
5 | background-repeat: no-repeat, no-repeat;
6 | }
7 |
--------------------------------------------------------------------------------
/app/controllers/care_plan_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | class CarePlanController < ApplicationController
3 | def index
4 | @bookmarked_strategies = current_user.strategies.where(bookmarked: true)
5 | @contacts = current_user.care_plan_contacts.order('LOWER(name)')
6 | @bookmarked_moments = current_user.moments.where(bookmarked: true)
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/app/controllers/concerns/care_plan_contacts_concern.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | module CarePlanContactsConcern
3 | extend ActiveSupport::Concern
4 |
5 | def create_response_object(care_plan_contact)
6 | return unless care_plan_contact.save!
7 |
8 | { id: care_plan_contact.id,
9 | name: care_plan_contact.name, phone: care_plan_contact.phone }
10 | end
11 |
12 | def update_response_object(care_plan_contact)
13 | return unless care_plan_contact.update!(care_plan_contact_params)
14 |
15 | { id: care_plan_contact.id,
16 | name: care_plan_contact.name, phone: care_plan_contact.phone }
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/app/controllers/concerns/moment_templates_concern.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | module MomentTemplatesConcern
3 | extend ActiveSupport::Concern
4 |
5 | def create_response_object(moment_template)
6 | return unless moment_template.save!
7 |
8 | { id: moment_template.id,
9 | name: moment_template.name, description: moment_template.description }
10 | end
11 |
12 | def update_response_object(moment_template)
13 | return unless moment_template.update!(moment_template_params)
14 |
15 | { id: moment_template.id,
16 | name: moment_template.name, description: moment_template.description }
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/app/controllers/concerns/moments_concern.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | module MomentsConcern
3 | extend ActiveSupport::Concern
4 |
5 | included do
6 | helper_method :publishing?, :saving_as_draft?,
7 | :empty_array_for
8 | end
9 |
10 | def publishing?
11 | params[:publishing] == '1'
12 | end
13 |
14 | def saving_as_draft?
15 | !publishing?
16 | end
17 |
18 | def empty_array_for(*symbols)
19 | symbols.each do |symbol|
20 | @moment[symbol] = [] if moment_params[symbol].nil? && @moment.has_attribute?(symbol)
21 | end
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/app/controllers/concerns/page_redirect_concern.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | module PageRedirectConcern
3 | extend ActiveSupport::Concern
4 |
5 | included do
6 | helper_method :if_not_signed_in, :if_not_admin, :redirect_to_path
7 | end
8 |
9 | def if_not_signed_in
10 | return if user_signed_in?
11 |
12 | redirect_to_path(new_user_session_path)
13 | end
14 |
15 | def if_not_admin
16 | return redirect_to_path(new_user_session_path) unless user_signed_in?
17 |
18 | return if current_user.admin?
19 |
20 | redirect_to_path('/')
21 | end
22 |
23 | def redirect_to_path(path)
24 | respond_to do |format|
25 | format.html { redirect_to path }
26 | format.json { head :no_content }
27 | end
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/app/controllers/concerns/shared_basic_concern.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | module SharedBasicConcern
3 | extend ActiveSupport::Concern
4 | include Shared
5 |
6 | def shared_quick_create_basic(model_class, params)
7 | model_name = model_class.name.downcase
8 | model_object = model_class.new(
9 | user_id: current_user.id,
10 | name: params[model_name][:name],
11 | description: params[model_name][:description]
12 | )
13 | shared_quick_create(model_object)
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/app/controllers/errors_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class ErrorsController < ApplicationController
4 | skip_before_action :if_not_signed_in
5 |
6 | def not_found
7 | render status: :not_found
8 | end
9 |
10 | def internal_server_error
11 | render status: :internal_server_error
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/app/controllers/locales_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class LocalesController < ApplicationController
4 | skip_before_action :if_not_signed_in
5 |
6 | def set_initial_locale
7 | if current_user
8 | current_user.update!(locale: params[:locale])
9 | else
10 | cookies['locale'] = params[:locale]
11 | end
12 |
13 | redirect_to root_path
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/app/controllers/registrations_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | class RegistrationsController < Devise::RegistrationsController
3 | protected
4 |
5 | def after_update_path_for(_resource)
6 | edit_user_registration_path
7 | end
8 |
9 | def update_resource(resource, params)
10 | if oauth_provider?(current_user.provider)
11 | params.delete('current_password')
12 | resource.update_without_password(params)
13 | else
14 | cookies.delete(:pwned)
15 | resource.update_with_password(params)
16 | end
17 | end
18 |
19 | def oauth_provider?(provider)
20 | %w[google_oauth2 facebook].include? provider
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/app/helpers/calendar_helper.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module CalendarHelper
4 | def new_cal_refill_reminder_needed?(medication)
5 | (medication.add_to_google_cal && medication.refill &&
6 | (medication.add_to_google_cal_changed? || medication.refill_changed?))
7 | .present?
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/app/helpers/dashboard_nav_helper.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DashboardNavHelper
4 | include ApplicationHelper
5 |
6 | def dashboard_nav_link_to(label, url, html_options = {})
7 | environment = html_options[:method] ? { method: html_options[:method] } : {}
8 | active_class = active?(url, environment) ? 'dashboardNavLinksActive' : ''
9 | html_options[:class] = active_class
10 | link_to(label, url, html_options)
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/app/helpers/date_time_helper.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DateTimeHelper
4 | def format_date(date_str)
5 | begin
6 | date_formatted = date_str.to_date
7 | rescue ArgumentError, NoMethodError
8 | date_formatted = Date.strptime(date_str, '%m/%d/%Y')
9 | end
10 | I18n.l(date_formatted, format: :long)
11 | end
12 |
13 | def format_time(time_str)
14 | I18n.l(Time.zone.parse(time_str), format: '%I:%M %p')
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/app/helpers/medication_refill_helper.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module MedicationRefillHelper
4 | include CalendarHelper
5 |
6 | def save_refill_to_google_calendar(medication)
7 | upload_to_calendar(medication)
8 | true
9 | rescue Google::Apis::ClientError
10 | return_to_sign_in
11 | false
12 | rescue Google::Apis::ServerError
13 | redirect_to_medication(medication)
14 | false
15 | end
16 |
17 | private
18 |
19 | def upload_to_calendar(medication)
20 | return unless current_user.oauth_enabled? &&
21 | new_cal_refill_reminder_needed?(medication)
22 |
23 | summary = t('medications.event_summary', name: medication.name)
24 |
25 | CalendarUploader
26 | .new(current_user.access_token)
27 | .upload_event(summary, medication.refill)
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/app/helpers/profile_helper.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module ProfileHelper
4 | include ApplicationHelper
5 | include StoriesHelper
6 | include MomentsHelper
7 |
8 | def data_json
9 | {
10 | data: moments_or_strategy_props(@stories),
11 | lastPage: @stories.last_page?
12 | }
13 | end
14 |
15 | def setup_stories
16 | @profile = if current_user.uid == params[:uid]
17 | current_user
18 | else
19 | User.find_by(uid: params[:uid])
20 | end
21 |
22 | return unless @profile == current_user ||
23 | current_user.mutual_allies?(@profile)
24 |
25 | @stories = Kaminari.paginate_array(get_stories(@profile))
26 | .page(params[:page])
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/app/helpers/reports_helper.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | module ReportsHelper
3 | include FormHelper
4 |
5 | def new_report_props(uid, comment_id = nil)
6 | new_form_props(
7 | report_form_inputs,
8 | reports_path(uid:, comment_id:)
9 | )
10 | end
11 |
12 | private
13 |
14 | def report_form_inputs
15 | [
16 | {
17 | id: 'report_reasons',
18 | type: 'textarea',
19 | name: 'report[reasons]',
20 | label: t('reports.reasons')
21 | }.merge(value: nil, required: true, dark: true)
22 | ]
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/app/helpers/visible_helper.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | module VisibleHelper
3 | def get_visible(visible)
4 | return t('shared.stats.visible_in_stats') if visible
5 |
6 | t('shared.stats.not_visible_in_stats')
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/app/mailers/ally_notifications/accepted_ally_request.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module AllyNotifications
4 | # Class helper to build accepted ally request message
5 | class AcceptedAllyRequest
6 | def initialize(recipient, data)
7 | @recipient = recipient
8 | @data = data
9 | end
10 |
11 | def to
12 | @recipient.email
13 | end
14 |
15 | def subject
16 | I18n.t('mailers.accepted_ally_request.subject', ally_name: @data[:user])
17 | end
18 |
19 | def message
20 | I18n.t('mailers.accepted_ally_request.message', ally_name: @data[:user])
21 | end
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/app/mailers/ally_notifications/new_ally_request.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module AllyNotifications
4 | # Class helper to build new ally request message
5 | class NewAllyRequest
6 | include ::UrlHelper
7 |
8 | def initialize(recipient, data)
9 | @recipient = recipient
10 | @data = data
11 | end
12 |
13 | def to
14 | @recipient.email
15 | end
16 |
17 | def subject
18 | I18n.t('mailers.new_ally_request.subject', ally_name: @data[:user])
19 | end
20 |
21 | def message
22 | I18n.t('mailers.new_ally_request.message', allies_url:)
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/app/mailers/banned_mailer.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | class BannedMailer < ApplicationMailer
3 | default from: ENV.fetch('SMTP_FROM', nil)
4 |
5 | def add_ban_email(recipient)
6 | @recipient = recipient
7 | mail(
8 | to: @recipient.email,
9 | subject: t('notifications.mailer.add_ban_subject')
10 | )
11 | end
12 |
13 | def remove_ban_email(recipient)
14 | @recipient = recipient
15 | mail(
16 | to: @recipient.email,
17 | subject: t('notifications.mailer.remove_ban_subject')
18 | )
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/app/mailers/custom_devise_mailer.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | class CustomDeviseMailer < Devise::Mailer
3 | before_action :load_logo_inline
4 |
5 | protected
6 |
7 | def load_logo_inline
8 | attachments.inline['logo@2x.png'] = File.read('./public/logo@2x.png')
9 | end
10 |
11 | def subject_for(key)
12 | return super unless key.to_s == 'invitation_instructions'
13 |
14 | if @resource.invited_by&.name
15 | I18n.t(
16 | 'devise.mailer.invitation_instructions.subject',
17 | name: @resource.invited_by&.name
18 | )
19 | else
20 | I18n.t('devise.mailer.invitation_instructions.subject_nameless')
21 | end
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/app/mailers/report_mailer.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | class ReportMailer < ApplicationMailer
3 | default from: ENV.fetch('SMTP_FROM', nil)
4 |
5 | def reported_email(recipient, reportee)
6 | @recipient = recipient
7 | @reportee = reportee
8 | mail(
9 | to: @recipient.email,
10 | subject: t('notifications.mailer.reported_user_subject')
11 | )
12 | end
13 |
14 | def reportee_email(recipient)
15 | @recipient = recipient
16 | mail(
17 | to: @recipient.email,
18 | subject: t('notifications.mailer.reportee_user_subject')
19 | )
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/app/models/application_record.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class ApplicationRecord < ActiveRecord::Base
4 | self.abstract_class = true
5 |
6 | def self.build_csv_rows(objects)
7 | return [] if objects.blank?
8 |
9 | klass = objects.klass
10 | data = [["#{klass.name.underscore}_info"]]
11 | attributes = if klass.const_defined?(:USER_DATA_ATTRIBUTES)
12 | klass.const_get(:USER_DATA_ATTRIBUTES)
13 | else
14 | klass.column_names
15 | end
16 | data << attributes
17 | objects.each do |object|
18 | data << attributes.map { |attribute| object.send(attribute.to_sym) }
19 | end
20 | data
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/app/models/care_plan_contact.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # == Schema Information
3 | #
4 | # Table name: care_plan_contacts
5 | #
6 | # id :bigint not null, primary key
7 | # name :string
8 | # phone :string
9 | # user_id :integer
10 | # created_at :datetime
11 | # updated_at :datetime
12 | #
13 |
14 | class CarePlanContact < ApplicationRecord
15 | USER_DATA_ATTRIBUTES = %w[
16 | id
17 | name
18 | phone
19 | created_at
20 | updated_at
21 | ].map!(&:freeze).freeze
22 |
23 | validates :user_id, :name, presence: true
24 | belongs_to :user
25 | end
26 |
--------------------------------------------------------------------------------
/app/models/concerns/is_visible_concern.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | module IsVisibleConcern
3 | extend ActiveSupport::Concern
4 |
5 | included do
6 | scope :is_visible, -> { where(visible: true) }
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/app/models/concerns/viewer.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Viewer
4 | extend ActiveSupport::Concern
5 |
6 | def viewer?(user)
7 | id = user&.id || user
8 | viewers.include?(id)
9 | end
10 |
11 | class_methods do
12 | def destroy_viewer(user_id, viewer_id)
13 | where(user_id:).find_each do |instance|
14 | viewers = instance.viewers
15 |
16 | if viewers.include?(viewer_id)
17 | viewers.delete(viewer_id)
18 | update(instance.id, viewers:)
19 | end
20 | end
21 | end
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/app/models/moment_template.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # == Schema Information
3 | #
4 | # Table name: moment_templates
5 | #
6 | # id :bigint not null, primary key
7 | # name :string
8 | # description :text
9 | # slug :string
10 | # user_id :bigint
11 | # created_at :datetime not null
12 | # updated_at :datetime not null
13 | #
14 |
15 | class MomentTemplate < ApplicationRecord
16 | extend FriendlyId
17 |
18 | friendly_id :name
19 | validates :user_id, :name, :description, presence: true
20 | belongs_to :user
21 |
22 | USER_DATA_ATTRIBUTES = %w[
23 | id
24 | name
25 | description
26 | created_at
27 | updated_at
28 | slug
29 | ].map!(&:freeze).freeze
30 | end
31 |
--------------------------------------------------------------------------------
/app/models/moments_category.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # == Schema Information
3 | #
4 | # Table name: moments_categories
5 | #
6 | # id :bigint not null, primary key
7 | # moment_id :integer
8 | # category_id :integer
9 | #
10 |
11 | class MomentsCategory < ApplicationRecord
12 | belongs_to :moment
13 | belongs_to :category
14 |
15 | validates :moment_id, uniqueness: { scope: :category_id }
16 | end
17 |
--------------------------------------------------------------------------------
/app/models/moments_mood.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # == Schema Information
3 | #
4 | # Table name: moments_moods
5 | #
6 | # id :bigint not null, primary key
7 | # moment_id :integer
8 | # mood_id :integer
9 | #
10 |
11 | class MomentsMood < ApplicationRecord
12 | belongs_to :moment
13 | belongs_to :mood
14 |
15 | validates :moment_id, uniqueness: { scope: :mood_id }
16 | end
17 |
--------------------------------------------------------------------------------
/app/models/moments_strategy.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # == Schema Information
3 | #
4 | # Table name: moments_strategies
5 | #
6 | # id :bigint not null, primary key
7 | # moment_id :integer
8 | # strategy_id :integer
9 | #
10 |
11 | class MomentsStrategy < ApplicationRecord
12 | belongs_to :moment
13 | belongs_to :strategy
14 |
15 | validates :moment_id, uniqueness: { scope: :strategy_id }
16 | end
17 |
--------------------------------------------------------------------------------
/app/models/perform_strategy_reminder.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # == Schema Information
4 | #
5 | # Table name: perform_strategy_reminders
6 | #
7 | # id :integer not null, primary key
8 | # strategy_id :integer not null
9 | # active :boolean not null
10 | # created_at :datetime
11 | # updated_at :datetime
12 | #
13 |
14 | class PerformStrategyReminder < ApplicationRecord
15 | belongs_to :strategy
16 | validates :active, inclusion: { in: [true, false] }
17 | scope :active, -> { where(active: true) }
18 |
19 | def name
20 | I18n.t('common.daily_reminder')
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/app/models/refill_reminder.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # == Schema Information
4 | #
5 | # Table name: refill_reminders
6 | #
7 | # id :integer not null, primary key
8 | # medication_id :integer not null
9 | # active :boolean not null
10 | # created_at :datetime
11 | # updated_at :datetime
12 | #
13 |
14 | class RefillReminder < ApplicationRecord
15 | belongs_to :medication
16 | validates :active, inclusion: { in: [true, false] }
17 | scope :active, -> { where(active: true) }
18 |
19 | def name
20 | I18n.t('medications.refill_reminder')
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/app/models/strategies_category.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # == Schema Information
3 | #
4 | # Table name: strategies_categories
5 | #
6 | # id :bigint not null, primary key
7 | # strategy_id :integer
8 | # category_id :integer
9 | #
10 |
11 | class StrategiesCategory < ApplicationRecord
12 | belongs_to :strategy
13 | belongs_to :category
14 |
15 | validates :strategy_id, uniqueness: { scope: :category_id }
16 | end
17 |
--------------------------------------------------------------------------------
/app/models/support.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | # == Schema Information
3 | #
4 | # Table name: supports
5 | #
6 | # id :bigint not null, primary key
7 | # user_id :integer
8 | # support_type :string
9 | # support_ids :text
10 | # created_at :datetime
11 | # updated_at :datetime
12 | #
13 |
14 | class Support < ApplicationRecord
15 | validates :user_id, :support_type, :support_ids, presence: true
16 | serialize :support_ids, Array
17 | validates :support_type, inclusion: %w[category mood moment strategy]
18 | before_save :array_data
19 |
20 | def array_data
21 | return unless support_ids.is_a?(Array)
22 |
23 | self.support_ids = support_ids.collect(&:to_i)
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/app/models/take_medication_reminder.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # == Schema Information
4 | #
5 | # Table name: take_medication_reminders
6 | #
7 | # id :integer not null, primary key
8 | # medication_id :integer not null
9 | # active :boolean not null
10 | # created_at :datetime
11 | # updated_at :datetime
12 | #
13 |
14 | class TakeMedicationReminder < ApplicationRecord
15 | belongs_to :medication
16 | validates :active, inclusion: { in: [true, false] }
17 | scope :active, -> { where(active: true) }
18 | scope :for_day, lambda { |day = Time.current.wday|
19 | joins(:medication).where('? = any(medications.weekly_dosage)', day)
20 | }
21 |
22 | def name
23 | I18n.t('common.daily_reminder')
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/app/models/users.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | module Users
3 | def self.table_name_prefix
4 | 'users_'
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/app/services/comment_notifications_service.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class CommentNotificationsService
4 | attr_reader :comment_id, :model_name
5 |
6 | def initialize(comment_id:, model_name:)
7 | @comment_id = comment_id
8 | @model_name = model_name
9 | end
10 |
11 | def self.remove(**args)
12 | new(**args).remove
13 | end
14 |
15 | def remove
16 | Comment.find(comment_id).destroy
17 | public_uniqueid = "comment_on_#{model_name}_#{comment_id}"
18 | Notification.where(uniqueid: public_uniqueid).destroy_all
19 | private_uniqueid = "comment_on_#{model_name}_private_#{comment_id}"
20 | Notification.where(uniqueid: private_uniqueid).destroy_all
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/app/services/medication_reminders.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class MedicationReminders
4 | def send_take_medication_reminder_emails
5 | TakeMedicationReminder.active.for_day.each do |reminder|
6 | NotificationMailer.take_medication(reminder).deliver_now
7 | end
8 | end
9 |
10 | def send_refill_reminder_emails
11 | ready_for_refill.each do |reminder|
12 | NotificationMailer.refill_medication(reminder).deliver_now
13 | end
14 | end
15 |
16 | private
17 |
18 | def ready_for_refill
19 | RefillReminder.active
20 | .joins(:medication)
21 | .where('medications.refill': one_week_from_now_as_string)
22 | end
23 |
24 | def one_week_from_now_as_string
25 | 1.week.from_now.strftime('%m/%d/%Y')
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/app/services/medium.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'open-uri'
4 | require 'json'
5 |
6 | class Medium
7 | def posts
8 | content_hash['items']
9 | end
10 |
11 | private
12 |
13 | def content_hash
14 | JSON.parse(content)
15 | end
16 |
17 | def content
18 | content = ''
19 | URI.open('https://api.rss2json.com/v1/api.json?rss_url=https://medium.com/feed/ifme') do |file|
20 | file.each_line { |line| content += line }
21 | end
22 | content
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/app/services/meeting_reminders.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Public: Used for sending reminders regarding upcoming meetings
4 | class MeetingReminders
5 | def send_meeting_reminder_emails
6 | meetings_tomorrow.each do |meeting|
7 | meeting.members.each do |member|
8 | NotificationMailer.meeting_reminder(meeting, member).deliver_now
9 | end
10 | end
11 | end
12 |
13 | private
14 |
15 | def meetings_tomorrow
16 | tomorrow_as_string = 1.day.from_now.strftime('%m/%d/%Y')
17 | Meeting.where(date: tomorrow_as_string)
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/app/services/recaptcha_service.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | class RecaptchaService
3 | MIN_ATTEMPTS_FOR_RECAPTCHA = 3
4 |
5 | def initialize(user)
6 | @user = user
7 | end
8 |
9 | def self.recaptcha_configured?
10 | Recaptcha.configuration.site_key.present? &&
11 | Recaptcha.configuration.secret_key.present?
12 | end
13 |
14 | def recaptcha_required_for_login?
15 | return false unless self.class.recaptcha_configured?
16 |
17 | failed_attempts = @user.failed_attempts.to_i
18 | failed_attempts >= MIN_ATTEMPTS_FOR_RECAPTCHA
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/app/services/strategy_reminders.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class StrategyReminders
4 | def send_perform_strategy_reminder_emails
5 | PerformStrategyReminder.active.each do |reminder|
6 | NotificationMailer.perform_strategy(reminder).deliver_now
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/app/views/banned_mailer/add_ban_email.html.erb:
--------------------------------------------------------------------------------
1 | <%= sanitize(t('notifications.mailer.add_ban_body', code_of_conduct_link: link_to(t('navigation.code_of_conduct'), 'https://www.contributor-covenant.org/'))) %>
--------------------------------------------------------------------------------
/app/views/banned_mailer/remove_ban_email.html.erb:
--------------------------------------------------------------------------------
1 | <%= sanitize(t('notifications.mailer.remove_ban_body', code_of_conduct_link: link_to(t('navigation.code_of_conduct'), 'https://www.contributor-covenant.org/'))) %>
--------------------------------------------------------------------------------
/app/views/categories/_category.html.erb:
--------------------------------------------------------------------------------
1 | <%= render partial: '/stories/category_or_mood', locals: { item: category } %>
2 |
--------------------------------------------------------------------------------
/app/views/categories/edit.html.erb:
--------------------------------------------------------------------------------
1 | <% title "#{t('common.actions.edit_instance', instance: @category.name)}" %>
2 | <%= react_component('Form', props: edit_category_props) %>
3 |
--------------------------------------------------------------------------------
/app/views/categories/new.html.erb:
--------------------------------------------------------------------------------
1 | <% title "#{t('categories.new')}" %>
2 | <%= react_component('Form', props: new_category_props) %>
3 |
--------------------------------------------------------------------------------
/app/views/categories/show.html.erb:
--------------------------------------------------------------------------------
1 | <% title @category.name %>
2 | <% if !@category.description.blank? && @category.description.length > 0 %>
3 | <%= sanitize(@category.description) %>
4 | <% else %>
5 |
6 | <%= t('warnings.no_description') %>
7 |
8 |
9 | <%= t('warnings.yes_description') %>
10 |
11 | <% end %>
12 |
13 |
14 |
<%= t('common.actions.plural') %>
15 | <%= react_component('StoryActions', props: element_visibility_based_props(@category))%>
16 |
17 |
18 | <%= render partial: '/tag_usage/index' %>
19 |
--------------------------------------------------------------------------------
/app/views/devise/confirmations/new.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %>
2 | <%= render "devise/shared/error_messages", resource: resource %>
3 |
4 |
5 | <%= react_component 'Input', props: {
6 | type: 'email',
7 | name: 'user[email]',
8 | id: 'user_email',
9 | label: t('common.form.email'),
10 | light: true,
11 | required: true
12 | } %>
13 |
14 | <%= f.submit t('devise.confirmations.resend_confirmation'), class: 'buttonGhostM marginTop' %>
15 | <% end %>
16 |
17 | <%= render "devise/shared/links" %>
18 |
--------------------------------------------------------------------------------
/app/views/devise/mailer/confirmation_instructions.html.erb:
--------------------------------------------------------------------------------
1 | <%= t('salutation', name: @email) %>
2 |
3 | <%= t('devise.mailer.confirmation.link_instructions') %>:
4 |
5 | <%= link_to t('devise.mailer.confirmation.link_text'), confirmation_url(@resource, confirmation_token: @token) %>
6 |
--------------------------------------------------------------------------------
/app/views/devise/mailer/reset_password_instructions.html.erb:
--------------------------------------------------------------------------------
1 | <%= t('salutation', name: @email) %>
2 |
3 | <%= t('devise.mailer.confirmation.link_instructions') %>
4 |
5 | <%= link_to t('devise.mailer.confirmation.link_text'), edit_password_url(@resource, reset_password_token: @token) %>
6 |
7 | <%= t('devise.mailer.reset_password.ignore') %>
8 | <%= t('devise.mailer.reset_password.info') %>
9 |
--------------------------------------------------------------------------------
/app/views/devise/mailer/unlock_instructions.html.erb:
--------------------------------------------------------------------------------
1 | <%= t('salutation', name: @email) %>
2 |
3 | <%=t('devise.mailer.unlock.info') %>
4 |
5 | <%=t('devise.mailer.unlock.link_instructions') %>
6 |
7 | <%= link_to t('devise.mailer.unlock.link_text'), unlock_url(@resource, unlock_token: @token) %>
8 |
--------------------------------------------------------------------------------
/app/views/devise/passwords/new.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %>
2 | <%= render "devise/shared/error_messages", resource: resource %>
3 |
4 |
5 | <%= react_component 'Input', props: {
6 | type: 'email',
7 | name: 'user[email]',
8 | id: 'user_email',
9 | label: t('common.form.email'),
10 | light: true,
11 | required: true
12 | } %>
13 |
14 | <%= f.submit t('devise.passwords.new.send_instructions'), class: 'buttonGhostM marginTop' %>
15 | <% end %>
16 |
17 | <%= render 'devise/shared/links' %>
18 |
--------------------------------------------------------------------------------
/app/views/devise/unlocks/new.html.erb:
--------------------------------------------------------------------------------
1 | Resend unlock instructions
2 |
3 | <%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| %>
4 | <%= render "devise/shared/error_messages", resource: resource %>
5 |
6 | <%= react_component 'Input', props: {
7 | type: 'email',
8 | name: 'user[email]',
9 | id: 'user_email',
10 | label: t('common.form.email'),
11 | light: true,
12 | required: true
13 | } %>
14 |
15 | <%= f.submit t('devise.unlock.resend'), class: 'buttonGhostM marginTop' %>
16 | <% end %>
17 |
18 | <%= render 'devise/shared/links' %>
19 |
--------------------------------------------------------------------------------
/app/views/errors/internal_server_error.html.erb:
--------------------------------------------------------------------------------
1 | <% title 'Error' %>
2 |
3 |
4 | <%= t('errors.internal_server_error.header_message') %>
5 |
6 |
7 |
8 | <%= link_to t('errors.home_page'), root_url %>
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/views/errors/not_found.html.erb:
--------------------------------------------------------------------------------
1 | <% title 'Error' %>
2 |
3 |
4 | <%= t('errors.not_found.header_message') %>
5 |
6 |
7 |
8 | <%= link_to t('errors.home_page'), root_url %>
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/views/groups/_members.html.erb:
--------------------------------------------------------------------------------
1 | <% group.members.each do |member| %>
2 |
3 | <%= link_to group.leaders.include?(member) ? "#{member.name} #{t('groups.index.leader')}" : member.name, profile_index_path(uid: member.uid) %>
4 | <% if member != current_user &&
5 | group.instance_of?(Group) &&
6 | group.leaders.include?(current_user) %>
7 | <%= kick_member_link(group, member) %>
8 | <% end %>
9 |
10 | <% end %>
11 |
--------------------------------------------------------------------------------
/app/views/groups/edit.html.erb:
--------------------------------------------------------------------------------
1 | <% title "#{t('common.actions.edit_instance', instance: @group.name)}" %>
2 | <%= react_component('Form', props: edit_group_props) %>
3 |
--------------------------------------------------------------------------------
/app/views/groups/new.html.erb:
--------------------------------------------------------------------------------
1 | <% title t('groups.new') %>
2 | <%= react_component('Form', props: new_group_props) %>
3 |
--------------------------------------------------------------------------------
/app/views/layouts/mailer.text.erb:
--------------------------------------------------------------------------------
1 | <%= yield %>
2 |
3 | ---
4 |
5 | <%= t('layouts.mailer.html.app_description',
6 | app_name: link_to(t('app_name'), root_url)
7 | ).html_safe %>
8 |
9 | <%= t('layouts.mailer.html.no_reply',
10 | email: link_to(t('email'), "mailto:join.ifme@gmail.com")
11 | ).html_safe %>
12 |
13 | <%= sanitize t('shared.footer.licence_subtitle',
14 | licence: link_to(t('shared.footer.licence'), 'https://github.com/ifmeorg/ifme/blob/main/LICENSE.txt', target: 'blank'))
15 | %>
16 |
--------------------------------------------------------------------------------
/app/views/medications/_medication.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= react_component('Story',
3 | html_options: html_options,
4 | props: present_medication(medication)) %>
5 |
6 |
--------------------------------------------------------------------------------
/app/views/medications/edit.html.erb:
--------------------------------------------------------------------------------
1 | <% title "#{t('common.actions.edit_instance', instance: @medication.name)}" %>
2 | <%= react_component('Form', props: edit_medication_props) %>
3 |
--------------------------------------------------------------------------------
/app/views/medications/new.html.erb:
--------------------------------------------------------------------------------
1 | <% title "#{t('medications.new')}" %>
2 | <%= react_component('Form', props: new_medication_props) %>
3 |
--------------------------------------------------------------------------------
/app/views/meetings/_story_body.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%= t('common.form.location') %>:
4 |
5 |
6 | <% if meeting.location.match(/^https?:\/\/|www\./) %>
7 | <%= link_to meeting.location, meeting.location %>
8 | <% else %>
9 | <%= link_to meeting.location,
10 | "https://www.google.com/maps/place/" + meeting.location %>
11 | <% end %>
12 |
13 |
14 |
15 | <%= t('common.date') %>:
16 |
17 | <%= format_date(meeting.date) %>
18 |
19 |
20 |
21 | <%= t('meetings.info.meeting_time') %>:
22 |
23 | <%= format_time(meeting.time) %>
24 |
25 |
26 |
27 | <%= get_meeting_members(meeting) %>
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/views/meetings/edit.html.erb:
--------------------------------------------------------------------------------
1 | <% title "#{t('common.actions.edit_instance', instance: @meeting.name)}" %>
2 | <%= react_component('Form', props: edit_meeting_props(@meeting)) %>
3 |
--------------------------------------------------------------------------------
/app/views/meetings/new.html.erb:
--------------------------------------------------------------------------------
1 | <% title "#{t('meetings.new')}" %>
2 | <%= react_component('Form', props: new_meeting_props(@group)) %>
3 |
--------------------------------------------------------------------------------
/app/views/moment_templates/index.html.erb:
--------------------------------------------------------------------------------
1 | <%= react_component('MomentTemplates', html_options: {}, props: {
2 | templates: @templates
3 | }) %>
4 |
--------------------------------------------------------------------------------
/app/views/moments/_moment.html.erb:
--------------------------------------------------------------------------------
1 | <%= render partial: '/stories/moment_or_strategy', locals: { item: moment } %>
2 |
--------------------------------------------------------------------------------
/app/views/moments/edit.html.erb:
--------------------------------------------------------------------------------
1 | <% title "#{t('common.actions.edit_instance', instance: @moment.name)}" %>
2 | <%= react_component('Form', props: edit_moment_props) %>
3 |
--------------------------------------------------------------------------------
/app/views/moments/new.html.erb:
--------------------------------------------------------------------------------
1 | <% title "#{t('moments.new')}" %>
2 | <%= react_component('Form', props: new_moment_props) %>
3 |
--------------------------------------------------------------------------------
/app/views/moods/_mood.html.erb:
--------------------------------------------------------------------------------
1 | <%= render partial: '/stories/category_or_mood', locals: { item: mood } %>
2 |
--------------------------------------------------------------------------------
/app/views/moods/edit.html.erb:
--------------------------------------------------------------------------------
1 | <% title "#{t('common.actions.edit_instance', instance: @mood.name)}" %>
2 | <%= react_component('Form', props: edit_mood_props) %>
3 |
--------------------------------------------------------------------------------
/app/views/moods/new.html.erb:
--------------------------------------------------------------------------------
1 | <% title "#{t('moods.new')}" %>
2 | <%= react_component('Form', props: new_mood_props) %>
3 |
--------------------------------------------------------------------------------
/app/views/moods/show.html.erb:
--------------------------------------------------------------------------------
1 | <% title @mood.name %>
2 | <% if @mood.description.present? && @mood.description.length > 0 %>
3 | <%= sanitize(@mood.description) %>
4 | <% else %>
5 |
6 | <%= t('warnings.no_description') %>
7 |
8 |
9 | <%= t('warnings.yes_description') %>
10 |
11 | <% end %>
12 |
13 |
14 |
<%= t('common.actions.plural') %>
15 | <%= react_component('StoryActions', props: element_visibility_based_props(@mood)) %>
16 |
17 |
18 | <%= render partial: '/tag_usage/index' %>
19 |
--------------------------------------------------------------------------------
/app/views/notification_mailer/meeting_reminder.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= t('salutation', name: @member.name) %>
3 |
4 |
5 | <%= t('meetings.reminder_mailer.body', meeting_name: @meeting.name, time: @meeting.time, location: @meeting.location) %>
6 |
7 |
--------------------------------------------------------------------------------
/app/views/notification_mailer/meeting_reminder.text.erb:
--------------------------------------------------------------------------------
1 | <%= t('salutation', name: @member.name) %>
2 |
3 | <%= t('meetings.reminder_mailer.body', meeting_name: @meeting.name, time: @meeting.time, location: @meeting.location) %>
4 |
--------------------------------------------------------------------------------
/app/views/notification_mailer/notification_email.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= t('salutation', name: @recipient.name) %>
3 |
4 |
5 | <%= sanitize(@message) %>
6 |
--------------------------------------------------------------------------------
/app/views/notification_mailer/notification_email.text.erb:
--------------------------------------------------------------------------------
1 | <%= t('salutation', name: @recipient.name) %>
2 | <%= sanitize(@message) %>
3 |
--------------------------------------------------------------------------------
/app/views/notification_mailer/perform_strategy.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= t('salutation', name: @user.name) %>
3 |
4 |
5 | <%= t('strategies.reminder_mailer.body', name: @model.name) %>
6 |
7 |
--------------------------------------------------------------------------------
/app/views/notification_mailer/perform_strategy.text.erb:
--------------------------------------------------------------------------------
1 | <%= t('salutation', name: @user.name) %>
2 | <%= t('strategies.reminder_mailer.body', name: @model.name) %>
3 |
--------------------------------------------------------------------------------
/app/views/notification_mailer/refill_medication.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= t('salutation', name: @user.name) %>
3 |
4 |
5 | <%= t('medications.refill_mailer.body',
6 | name: @model.name, refill: @model.refill) %>
7 |
8 |
--------------------------------------------------------------------------------
/app/views/notification_mailer/refill_medication.text.erb:
--------------------------------------------------------------------------------
1 | <%= t('salutation', name: @user.name) %>
2 | <%= t('medications.refill_mailer.body',
3 | name: @model.name, refill: @model.refill) %>
4 |
--------------------------------------------------------------------------------
/app/views/notification_mailer/take_medication.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= t('salutation', name: @user.name) %>
3 |
4 |
5 | <%= t('medications.reminder_mailer.body', name: @model.name) %>
6 |
7 |
--------------------------------------------------------------------------------
/app/views/notification_mailer/take_medication.text.erb:
--------------------------------------------------------------------------------
1 | <%= t('salutation', name: @user.name) %>
2 | <%= t('medications.reminder_mailer.body', name: @model.name) %>
3 |
--------------------------------------------------------------------------------
/app/views/pages/_update_password_modal.html.erb:
--------------------------------------------------------------------------------
1 | <% if user_signed_in? && cookies[:pwned] %>
2 | <%= react_component('Modal', props: {
3 | title: t('pages.home.update_pwd_modal.title'),
4 | body: t('pages.home.update_pwd_modal.body', update_password_link: link_to(t('pages.home.update_pwd_modal.update_link'), edit_user_registration_path)),
5 | open: true
6 | }) %>
7 | <% end %>
8 |
--------------------------------------------------------------------------------
/app/views/pages/home.html.erb:
--------------------------------------------------------------------------------
1 | <% if user_signed_in? && @stories.any? %>
2 | <% title t('pages.home.stories') %>
3 | <% @page_new = "New Moment" %>
4 | <% page_new new_moment_path %>
5 | <% elsif user_signed_in? %>
6 | <% title t('pages.home.signed_in_empty.main_message_one', name: current_user.name) %>
7 | <% end %>
8 |
9 | <% if !user_signed_in? %>
10 | <%= render partial: 'not_signed_in' %>
11 | <% elsif @stories.any? %>
12 | <%= react_component('BaseContainer', props: {
13 | container: 'StoryContainer',
14 | data: moments_or_strategy_props(@stories),
15 | fetchUrl: home_data_path,
16 | lastPage: @stories.last_page?
17 | }) %>
18 | <% else %>
19 | <%= render partial: 'signed_in_empty' %>
20 | <% end %>
21 |
22 | <%= render partial: 'update_password_modal' %>
23 |
--------------------------------------------------------------------------------
/app/views/pages/partners.html.erb:
--------------------------------------------------------------------------------
1 | <% title t('navigation.partners') %>
2 |
3 | <%= raw t('pages.partners.description',
4 | email: link_to(t('email'), "mailto:#{t('email')}")
5 | ) %>
6 |
7 | <%= print_partners(@organizations) %>
8 |
--------------------------------------------------------------------------------
/app/views/pages/press.html.erb:
--------------------------------------------------------------------------------
1 | <% title t('navigation.press') %>
2 |
3 |
4 | <% @press.each do |p| %>
5 |
6 | <%= react_component('Resource', props: {
7 | external: true,
8 | title: p['link_name'],
9 | link: p['link'],
10 | author: p['author']
11 | }) %>
12 |
13 | <% end %>
14 |
15 |
--------------------------------------------------------------------------------
/app/views/pages/resources.html.erb:
--------------------------------------------------------------------------------
1 | <% title t('navigation.resources') %>
2 | <%= react_component('Resources', props: { resources: @resources, keywords: @keywords }) %>
3 |
--------------------------------------------------------------------------------
/app/views/report_mailer/reported_email.html.erb:
--------------------------------------------------------------------------------
1 | <%= t('notifications.mailer.reported_user_body', reported_name: @reportee.name) %>
2 |
--------------------------------------------------------------------------------
/app/views/report_mailer/reportee_email.html.erb:
--------------------------------------------------------------------------------
1 | <%= t('notifications.mailer.reportee_user_body') %>
2 |
--------------------------------------------------------------------------------
/app/views/reports/new.html.erb:
--------------------------------------------------------------------------------
1 | <% title "#{t('reports.new', name: User.find_by(uid: params[:uid]).name)}" %>
2 | <%= react_component('Form', props: new_report_props(params[:uid], params[:comment_id])) %>
3 |
--------------------------------------------------------------------------------
/app/views/search/_form.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_for(:search, url: search_index_path, html: { method: :get }) do |f| %>
2 |
3 | <%= react_component 'Input', props: {
4 | type: 'search',
5 | name: 'search[email]',
6 | id: 'search_email',
7 | label: t('search.form.search_by_email'),
8 | placeholder: t('search.form.search_by_email'),
9 | dark: true,
10 | value: @email || nil
11 | } %>
12 | <%= f.submit t('search.label'), class: 'searchSubmit buttonDarkL' %>
13 |
14 | <% end %>
15 |
--------------------------------------------------------------------------------
/app/views/shared/_comments.html.erb:
--------------------------------------------------------------------------------
1 | <%= react_component('Comments', props: {
2 | comments: @comments,
3 | formProps: comment_form_props(
4 | local_assigns[:commentable],
5 | local_assigns[:commentable].class.name
6 | )
7 | }) %>
8 |
--------------------------------------------------------------------------------
/app/views/shared/_dashboard_nav_actions.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= link_to(t('shared.header.signout'), destroy_user_session_path, method: :delete, class: 'buttonGhostS') %>
3 |
--------------------------------------------------------------------------------
/app/views/shared/_dashboard_nav_links.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <% if current_user.admin? %>
3 | <%= dashboard_nav_link_to(t('reports.admin_dashboard'), admin_dashboard_path) %>
4 | <% end %>
5 | <%= dashboard_nav_link_to(t('moments.plural'), moments_path) %>
6 | <%= dashboard_nav_link_to(t('categories.plural'), categories_path) %>
7 | <%= dashboard_nav_link_to(t('moods.plural'), moods_path) %>
8 | <%= dashboard_nav_link_to(t('strategies.plural'), strategies_path) %>
9 | <%= dashboard_nav_link_to(t('medications.index.title'), medications_path) %>
10 | <%= dashboard_nav_link_to(t('groups.plural'), groups_path) %>
11 | <%= dashboard_nav_link_to(t('care_plan.index.title'), care_plan_path) %>
12 | <%= dashboard_nav_link_to(t('allies.index.title'), allies_path) %>
13 |
14 |
--------------------------------------------------------------------------------
/app/views/shared/_dashboard_nav_mobile.html.erb:
--------------------------------------------------------------------------------
1 | <%= render partial: "shared/dashboard_nav_links" %>
2 | <%= render partial: "shared/dashboard_nav_actions" %>
3 |
--------------------------------------------------------------------------------
/app/views/shared/_page_author.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= ProfilePicture.fetch(local_assigns[:author].avatar.url, small: true) %>
3 | <%= link_to local_assigns[:author].name, profile_index_path(uid: local_assigns[:author].uid) %>
4 |
5 |
--------------------------------------------------------------------------------
/app/views/stories/_category_or_mood.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= react_component('Story',
3 | html_options: html_options,
4 | props: present_category_or_mood(local_assigns[:item])) %>
5 |
6 |
--------------------------------------------------------------------------------
/app/views/stories/_moment_or_strategy.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= react_component('Story',
3 | html_options: html_options,
4 | props: present_moment_or_strategy(local_assigns[:item])) %>
5 |
6 |
--------------------------------------------------------------------------------
/app/views/strategies/_strategy.html.erb:
--------------------------------------------------------------------------------
1 | <%= render partial: '/stories/moment_or_strategy', locals: { item: strategy } %>
2 |
--------------------------------------------------------------------------------
/app/views/strategies/edit.html.erb:
--------------------------------------------------------------------------------
1 | <% title "#{t('common.actions.edit_instance', instance: @strategy.name)}" %>
2 | <%= react_component('Form', props: edit_strategy_props(@strategy, @viewers)) %>
3 |
--------------------------------------------------------------------------------
/app/views/strategies/new.html.erb:
--------------------------------------------------------------------------------
1 | <% title "#{t('strategies.new')}" %>
2 | <%= react_component('Form', props: new_strategy_props(@strategy, @viewers)) %>
--------------------------------------------------------------------------------
/app/views/tag_usage/_index.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <% if @moments&.any? %>
3 |
<%= t('moments.tagged_moments') %> (<%= @total_moments %>)
4 | <%= render partial: '/tag_usage/stories', locals: { data: @moments, data_type: 'moment' } %>
5 | <% end %>
6 | <% if !@strategies.nil? && @strategies.any? %>
7 | <%= t('strategies.tagged_strategies') %> (<%= @total_strategies %>)
8 | <%= render partial: '/tag_usage/stories', locals: { data: @strategies, data_type: 'strategy' } %>
9 | <% end %>
10 |
11 |
--------------------------------------------------------------------------------
/app/views/tag_usage/_stories.html.erb:
--------------------------------------------------------------------------------
1 | <%= react_component('BaseContainer', props: {
2 | container: 'StoryContainer',
3 | data: moments_or_strategy_props(local_assigns[:data]),
4 | fetchUrl: local_assigns[:data_type] == 'moment' ? tagged_moments_path(category_id: @category&.id, mood_id: @mood&.id, strategy_id: @strategy&.id) : tagged_strategies_path(category_id: @category&.id),
5 | lastPage: local_assigns[:data].last_page?
6 | }) %>
7 |
--------------------------------------------------------------------------------
/app/views/users/invitations/new.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_for resource, as: resource_name, url: invitation_path(resource_name), html: { id: 'invitations', method: :post } do |f| %>
2 | <%= render "devise/shared/error_messages", resource: resource %>
3 | <%= react_component 'Input', props: {
4 | type: 'text',
5 | name: 'user[email]',
6 | id: 'user_email',
7 | label: t('common.form.email'),
8 | placeholder: t('allies.form.placeholder'),
9 | dark: true,
10 | required: true
11 | } %>
12 |
13 | <%= f.submit t('devise.invitations.new.submit_button'), class: 'buttonDarkM' %>
14 |
15 | <% end %>
16 |
--------------------------------------------------------------------------------
/app/views/users/mailer/invitation_instructions.html.erb:
--------------------------------------------------------------------------------
1 | <%= t("devise.mailer.invitation_instructions.hello", email: @resource.email) %>
2 |
3 |
4 | <%= t("devise.mailer.invitation_instructions.someone_invited_you", name: @resource.invited_by&.name, url: root_url) %>
5 |
6 |
7 | <%= link_to t("devise.mailer.invitation_instructions.accept"), accept_invitation_url(@resource, :invitation_token => @token) %>
8 |
9 | <% if @resource.invitation_due_at %>
10 |
11 |
12 | <%= t("devise.mailer.invitation_instructions.accept_until", due_date: @resource.invitation_due_at.strftime('%A %B %d, %Y at %I:%M %p')) %>
13 | <% end %>
14 |
15 |
16 |
17 | <%= t("devise.mailer.invitation_instructions.ignore").html_safe %>
18 |
--------------------------------------------------------------------------------
/app/views/users/mailer/invitation_instructions.text.erb:
--------------------------------------------------------------------------------
1 | <%= t("devise.mailer.invitation_instructions.hello", email: @resource.email) %>
2 |
3 | <%= t("devise.mailer.invitation_instructions.someone_invited_you", name: @resource.invited_by&.name, url: root_url) %>
4 |
5 | <%= accept_invitation_url(@resource, :invitation_token => @token) %>
6 |
7 | <% if @resource.invitation_due_at %>
8 | <%= t("devise.mailer.invitation_instructions.accept_until", due_date: @resource.invitation_due_at.strftime('%A %B %d, %Y at %I:%M %p')) %>
9 | <% end %>
10 |
11 | <%= strip_tags t("devise.mailer.invitation_instructions.ignore") %>
12 |
--------------------------------------------------------------------------------
/app/workers/delete_stale_data_worker.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | class DeleteStaleDataWorker
3 | include Sidekiq::Worker
4 |
5 | ACTIVE_DURATION = 30.days
6 |
7 | def perform
8 | Users::DataRequest
9 | .where('updated_at < ?', (Time.current - ACTIVE_DURATION))
10 | .where(status_id: Users::DataRequest::STATUS[:success])
11 | .each do |dr|
12 | File.delete(dr.file_path) if dr.file_path.present? && File.exist?(dr.file_path)
13 | dr.update(status_id: Users::DataRequest::STATUS[:deleted])
14 | end
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/app/workers/process_data_request_worker.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | class ProcessDataRequestWorker
3 | include Sidekiq::Worker
4 | sidekiq_options queue: 'critical'
5 |
6 | def perform(request_id)
7 | data_request = Users::DataRequest.find_by(request_id:)
8 | return if data_request.blank? ||
9 | data_request.status_id == Users::DataRequest::STATUS[:success]
10 |
11 | data_request.create_csv
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/bin/bundle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3 | load Gem.bin_path('bundler', 'bundle')
4 |
--------------------------------------------------------------------------------
/bin/client.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # This script is run from Procfile.dev (which is run from bin/start_app
4 | #
5 | # Make sure we're in the source directory by checking for the existence
6 | # of ./public (note that we're checking the relative path, not the absolute).
7 | #
8 | # bin/start_app should change to the source directory, so
9 | # this should never happen unless something very unusual is wrong
10 |
11 | if [ ! -d public ]; then
12 | {
13 | echo "Error in setup"
14 | exit $?
15 | }
16 | fi
17 |
18 | rails db:migrate RAILS_ENV=development
19 | rm -rf public/webpack/development/* || true && \
20 | cd client && \
21 | bundle exec rake react_on_rails:locale && \
22 | yarn install && \
23 | yarn build:development && \
24 |
25 | exit 0;
26 |
--------------------------------------------------------------------------------
/bin/install-git-hooks.bash:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | FILE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
4 |
5 | for f in ${FILE_DIR}/../git-hooks/*; do
6 | filename=$(basename ${f})
7 | ln -sf ${f} ${FILE_DIR}/../.git/hooks/${filename}
8 | done
9 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require_relative "../config/boot"
3 | require "rake"
4 | Rake.application.run
5 |
--------------------------------------------------------------------------------
/bin/spring:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | # This file loads spring without using Bundler, in order to be fast
4 | # It gets overwritten when you run the `spring binstub` command
5 |
6 | unless defined?(Spring)
7 | require 'rubygems'
8 | require 'bundler'
9 |
10 | if match = Bundler.default_lockfile.read.match(/^GEM$.*?^ spring \((.*?)\)$.*?^$/m)
11 | ENV['GEM_PATH'] = ([Bundler.bundle_path.to_s] + Gem.path).join(File::PATH_SEPARATOR)
12 | ENV['GEM_HOME'] = ''
13 | Gem.paths = ENV
14 |
15 | gem 'spring', match[1]
16 | require 'spring/binstub'
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/bin/start_app:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require 'pathname'
3 | require 'fileutils'
4 | include FileUtils
5 |
6 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
7 |
8 | chdir APP_ROOT do
9 | puts "\n== Installing gems =="
10 | system('bundle install')
11 | puts "\n== Installing npm packages =="
12 | system('cd client/ && yarn install && cd ..')
13 | puts "\n== Starting application server (foreman) =="
14 | system('foreman start -f Procfile.dev')
15 | end
16 |
--------------------------------------------------------------------------------
/bin/webpack:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
4 | ENV["NODE_ENV"] ||= "development"
5 |
6 | require "pathname"
7 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
8 | Pathname.new(__FILE__).realpath)
9 |
10 | require "bundler/setup"
11 |
12 | require "webpacker"
13 | require "webpacker/webpack_runner"
14 |
15 | APP_ROOT = File.expand_path("..", __dir__)
16 | Dir.chdir(APP_ROOT) do
17 | Webpacker::WebpackRunner.run(ARGV)
18 | end
19 |
--------------------------------------------------------------------------------
/bin/webpack-dev-server:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
4 | ENV["NODE_ENV"] ||= "development"
5 |
6 | require "pathname"
7 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
8 | Pathname.new(__FILE__).realpath)
9 |
10 | require "bundler/setup"
11 |
12 | require "webpacker"
13 | require "webpacker/dev_server_runner"
14 |
15 | APP_ROOT = File.expand_path("..", __dir__)
16 | Dir.chdir(APP_ROOT) do
17 | Webpacker::DevServerRunner.run(ARGV)
18 | end
19 |
--------------------------------------------------------------------------------
/client/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "@babel/env", {
5 | "useBuiltIns": "usage",
6 | "modules": "commonjs",
7 | "corejs": "3"
8 | }
9 | ],
10 | "@babel/preset-flow",
11 | "@babel/preset-react"
12 | ],
13 | "plugins": [
14 | "@babel/plugin-proposal-class-properties",
15 | "@babel/plugin-syntax-dynamic-import",
16 | "@babel/plugin-transform-modules-commonjs",
17 | "@babel/plugin-proposal-private-methods",
18 | "@babel/plugin-proposal-private-property-in-object"
19 | ],
20 | "env": {
21 | "test": {
22 | "plugins": [
23 | "babel-plugin-transform-es2015-modules-commonjs"
24 | ]
25 | },
26 | "development": {
27 | "plugins": [
28 | "flow-react-proptypes"
29 | ]
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/client/.eslintignore:
--------------------------------------------------------------------------------
1 | flow/
2 | flow-typed/
3 | default.js
4 | translations.js
5 |
--------------------------------------------------------------------------------
/client/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | flow-typed/
3 | translations.js
4 | default.js
5 | /coverage
6 | /storybook-static
7 | /.out*/*
8 | /.public*/*
9 | /app/libs/i18n/*.json
10 |
--------------------------------------------------------------------------------
/client/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "trailingComma": "es5",
3 | "singleQuote": true
4 | }
--------------------------------------------------------------------------------
/client/.storybook/preview.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */
2 | import React from 'react';
3 | import './stories.scss';
4 |
5 | export const parameters = {
6 | backgrounds: {
7 | default: 'light-grey',
8 | values: [
9 | { name: 'light-grey', value: '#D3D3D3' },
10 | { name: 'grey', value: '#808080' },
11 | { name: 'white', value: '#FFFFFF' },
12 | { name: 'mulberry', value: '#6D0839' },
13 | ],
14 | },
15 | viewMode: 'docs',
16 | };
17 |
--------------------------------------------------------------------------------
/client/.storybook/stories.scss:
--------------------------------------------------------------------------------
1 | @import "~styles/global.scss";
2 |
3 | /* This file is to override Storybook default styles */
4 |
5 | body {
6 | /* Needed to get Storybook Backgrounds Addon to work */
7 | background-color: transparent !important;
8 | height: auto !important;
9 | /* Add padding to story page to give it some space against the edges */
10 | padding: 20px !important;
11 | }
12 |
--------------------------------------------------------------------------------
/client/.stylelintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "stylelint-config-standard",
3 | "ignoreFiles": ["../node_modules/**/*.scss", "./node_modules/**/*.scss", "./app/styles/_global_font.scss"],
4 | "rules": {
5 | "at-rule-no-unknown": null,
6 | "no-descending-specificity": null
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/client/app/components/Avatar/Avatar.scss:
--------------------------------------------------------------------------------
1 | @import "~styles/_global.scss";
2 |
3 | .avatar {
4 | @include setFontSize($size-20);
5 |
6 | display: inline-block;
7 | text-align: center;
8 | }
9 |
10 | .image {
11 | border-radius: 50%;
12 | overflow: hidden;
13 | object-fit: cover;
14 | background: $mulberry-key-lime;
15 | height: 100px;
16 | width: 100px;
17 | margin: 0 auto;
18 | }
19 |
20 | .large {
21 | @include setFontSize($size-22);
22 |
23 | .image {
24 | height: 150px;
25 | width: 150px;
26 | }
27 | }
28 |
29 | .small {
30 | @include setFontSize($size-18);
31 |
32 | .image {
33 | height: 50px;
34 | width: 50px;
35 | }
36 | }
37 |
38 | .name {
39 | margin-top: 0.5em;
40 | }
41 |
--------------------------------------------------------------------------------
/client/app/components/BaseContainer/__tests__/StoryContainer.spec.jsx:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 | import { render } from '@testing-library/react';
4 | import StoryContainer from 'components/BaseContainer/StoryContainer';
5 |
6 | describe('StoryContainer', () => {
7 | it('renders correctly', () => {
8 | const { container } = render();
9 | expect(container.firstChild).not.toBeNull();
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/client/app/components/Blockquote/Blockquote.scss:
--------------------------------------------------------------------------------
1 | @import "~styles/_global.scss";
2 |
3 | .text {
4 | @include setFontSize($size-24);
5 |
6 | display: inline-block;
7 | position: relative;
8 | background-color: rgba(255, 255, 255, 0.1);
9 | font-style: italic;
10 | text-align: center;
11 | align-content: center;
12 | text-shadow: $size-0 $size-2 4px rgba(0, 0, 0, 0.25);
13 | width: 100%;
14 | padding: $size-50;
15 | color: $white;
16 |
17 | @media screen and (max-width: $medium) {
18 | padding: $size-20;
19 | }
20 |
21 | .author {
22 | @include setMargin($size-10, $size-0, $size-0, $size-0);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/client/app/components/Blockquote/index.jsx:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 | import type { Node } from 'react';
4 | import css from './Blockquote.scss';
5 |
6 | export type Props = {
7 | text?: string,
8 | author?: string,
9 | };
10 |
11 | export const Blockquote = (props: Props): Node => {
12 | const { text, author } = props;
13 | const textClassNames = `${css.text}`;
14 | const authorClassNames = `${css.author}`;
15 | return (
16 |
17 |
18 | {text}
19 |
20 | {author}
21 |
22 | );
23 | };
24 |
--------------------------------------------------------------------------------
/client/app/components/Chart/ChartControl.scss:
--------------------------------------------------------------------------------
1 | @import "~styles/_global.scss";
2 |
3 | .chartControl {
4 | > div:first-of-type {
5 | @include setMargin($size-0, $size-0, $size-20, $size-0);
6 |
7 | line-height: 2.5;
8 | }
9 |
10 | button {
11 | @include setMargin($size-0, $size-8, $size-0, $size-0);
12 |
13 | &:last-of-type {
14 | @include setMargin($size-0, $size-0, $size-0, $size-0);
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/client/app/components/Chart/index.jsx:
--------------------------------------------------------------------------------
1 | // @flow
2 | /* eslint react/jsx-props-no-spreading: 0 */
3 | import { Chart as ChartJS } from 'chart.js';
4 | import React from 'react';
5 | import type { Node } from 'react';
6 | import { AreaChart, LineChart } from 'react-chartkick';
7 |
8 | ChartJS.defaults.global.defaultFontFamily = 'Lato';
9 |
10 | type chartShape = {
11 | xtitle?: string,
12 | ytitle?: string,
13 | data?: Object | any[],
14 | chartType: 'Line' | 'Area',
15 | };
16 |
17 | const colorSchemes = ['#6D0839', '#66118', '#7F503F', '#775577', '#CCAADD'];
18 |
19 | export function Chart({ chartType, ...props }: chartShape): Node {
20 | return chartType === 'Line' ? (
21 |
22 | ) : (
23 |
24 | );
25 | }
26 |
--------------------------------------------------------------------------------
/client/app/components/Form/Form.scss:
--------------------------------------------------------------------------------
1 | @import "~styles/_global.scss";
2 |
3 | .form {
4 | > div {
5 | @include setMargin($size-0, $size-0, $size-20, $size-0);
6 |
7 | &:last-of-type {
8 | @include setMargin($size-0, $size-0, $size-0, $size-0);
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/client/app/components/Header/types.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | export type Link = {
4 | name: string,
5 | url: string,
6 | active?: boolean,
7 | dataMethod?: string,
8 | hideInMobile?: boolean,
9 | };
10 |
11 | export type Profile = {
12 | avatar?: string,
13 | name: string,
14 | profile: Link,
15 | account: Link,
16 | notifications: {
17 | plural: string,
18 | none: string,
19 | clear: string,
20 | },
21 | };
22 |
--------------------------------------------------------------------------------
/client/app/components/Input/InputPassword.scss:
--------------------------------------------------------------------------------
1 | @import "~styles/_global.scss";
2 |
3 | .password {
4 | display: flex;
5 | flex-direction: row;
6 |
7 | input {
8 | border-radius: $size-4 $size-0 $size-0 $size-4 !important;
9 | }
10 |
11 | button {
12 | @include setFontSize($size-20);
13 |
14 | background-color: $mulberry;
15 | border: 0;
16 | color: $white;
17 | border-radius: $size-0 $size-4 $size-4 $size-0;
18 | width: 70px;
19 | box-shadow: $size-0 $size-2 $size-10 $black-10;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/client/app/components/Input/InputRadioGroup.scss:
--------------------------------------------------------------------------------
1 | @import "~styles/_global.scss";
2 |
3 | .wrapper {
4 | display: flex;
5 | flex-direction: row;
6 |
7 | .content {
8 | margin-right: $size-16;
9 | }
10 |
11 | input {
12 | margin-right: $size-6;
13 | margin-left: $size-6;
14 | }
15 |
16 | label {
17 | all: unset;
18 | color: $mulberry-90;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/client/app/components/Input/__tests__/InputLabel.spec.jsx:
--------------------------------------------------------------------------------
1 | // @flow
2 | import { render, screen } from '@testing-library/react';
3 | import React from 'react';
4 | import { InputLabel } from 'components/Input/InputLabel';
5 |
6 | const label = 'Some Label';
7 | const info = 'Some Info';
8 |
9 | describe('InputLabel', () => {
10 | it('renders correctly', () => {
11 | render(
12 | ,
13 | );
14 | expect(screen.getByText(label)).toBeInTheDocument();
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/client/app/components/LoadMoreButton/LoadMoreButton.scss:
--------------------------------------------------------------------------------
1 | @import "~styles/_global.scss";
2 |
3 | .container {
4 | text-align: center;
5 | }
6 |
--------------------------------------------------------------------------------
/client/app/components/LoadMoreButton/index.jsx:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 | import type { Node } from 'react';
4 | import { I18n } from 'libs/i18n';
5 | import css from './LoadMoreButton.scss';
6 |
7 | export type Props = {
8 | onClick?: () => void,
9 | };
10 |
11 | const LoadMoreButton = ({ onClick }: Props): Node => (
12 |
13 |
20 |
21 | );
22 |
23 | export { LoadMoreButton };
24 |
--------------------------------------------------------------------------------
/client/app/components/Logo/index.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import { LogoFactory } from './LogoFactory';
3 |
4 | export const Logo: any = LogoFactory();
5 | Logo.displayName = 'Logo';
6 |
7 | export const LogoSolid: any = LogoFactory('solid');
8 | LogoSolid.displayName = 'LogoSolid';
9 |
--------------------------------------------------------------------------------
/client/app/components/OAuthButton/facebookIcon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client/app/components/OAuthButton/googleIcon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client/app/components/SkipToContent/SkipToContent.scss:
--------------------------------------------------------------------------------
1 | @import "~styles/_global.scss";
2 |
3 | .skipToContent {
4 | // accessibility hidden element
5 | height: 1px;
6 | left: -10000px;
7 | overflow: hidden;
8 | position: absolute;
9 | top: auto;
10 | width: 1px;
11 | // styling
12 | align-items: center;
13 | background: $cornflower;
14 | color: $carmine;
15 | display: flex;
16 | flex-direction: row;
17 | flex-wrap: wrap;
18 | justify-content: space-evenly;
19 | line-height: 3.5;
20 | margin-top: $size-4;
21 |
22 | &:focus {
23 | height: auto;
24 | width: auto;
25 | position: static;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/client/app/components/SkipToContent/__tests__/SkipToContent.spec.jsx:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 | import { render } from '@testing-library/react';
4 | import SkipToContent from 'components/SkipToContent';
5 |
6 | describe('SkipToContent', () => {
7 | it('renders correctly', () => {
8 | let wrapper;
9 | expect(() => {
10 | wrapper = render();
11 | }).not.toThrow();
12 | expect(wrapper).not.toBeNull();
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/client/app/components/SkipToContent/index.jsx:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 | import type { Node } from 'react';
4 |
5 | import { I18n } from 'libs/i18n';
6 | import css from './SkipToContent.scss';
7 |
8 | export type Props = {
9 | id: string,
10 | };
11 |
12 | const SkipToContent = ({ id }: Props): Node => (
13 |
14 | {I18n.t('navigation.skip_to_main_content')}
15 |
16 | );
17 |
18 | export default SkipToContent;
19 |
--------------------------------------------------------------------------------
/client/app/components/Story/StoryBy.jsx:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 | import type { Node } from 'react';
4 | import { Utils } from 'utils';
5 | import { Avatar } from 'components/Avatar';
6 | import css from './Story.scss';
7 |
8 | export type Props = {
9 | avatar?: string,
10 | author: any,
11 | };
12 |
13 | export const StoryBy = (props: Props): Node => {
14 | const { avatar, author } = props;
15 | return (
16 |
17 |
18 |
{Utils.renderContent(author)}
19 |
20 | );
21 | };
22 |
--------------------------------------------------------------------------------
/client/app/components/Story/StoryCategories.jsx:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 | import type { Node } from 'react';
4 | import { Tag } from 'components/Tag';
5 | import css from './Story.scss';
6 |
7 | export type Category = {
8 | name: string,
9 | slug: string,
10 | };
11 |
12 | export type Props = {
13 | categories: Category[],
14 | };
15 |
16 | export const StoryCategories = (props: Props): Node => {
17 | const { categories } = props;
18 | return (
19 |
20 | {categories.map((value) => (
21 |
22 | ))}
23 |
24 | );
25 | };
26 |
--------------------------------------------------------------------------------
/client/app/components/Story/StoryDate.jsx:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 | import type { Node } from 'react';
4 | import css from './Story.scss';
5 |
6 | export type Props = {
7 | date: string,
8 | };
9 |
10 | export const StoryDate = (props: Props): Node => {
11 | const { date } = props;
12 | return {date}
;
13 | };
14 |
--------------------------------------------------------------------------------
/client/app/components/Story/StoryDraft.jsx:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 | import type { Node } from 'react';
4 | import { Tag } from 'components/Tag';
5 | import css from './Story.scss';
6 |
7 | export type Props = {
8 | draft: string,
9 | };
10 |
11 | export const StoryDraft = (props: Props): Node => {
12 | const { draft } = props;
13 | return (
14 |
15 |
16 |
17 | );
18 | };
19 |
--------------------------------------------------------------------------------
/client/app/components/Story/StoryMoods.jsx:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 | import type { Node } from 'react';
4 | import { Tag } from 'components/Tag';
5 | import css from './Story.scss';
6 |
7 | export type Mood = {
8 | name: string,
9 | slug: string,
10 | };
11 |
12 | export type Props = {
13 | moods: Mood[],
14 | };
15 |
16 | export const StoryMoods = (props: Props): Node => {
17 | const { moods } = props;
18 | return (
19 |
20 | {moods.map((value) => (
21 |
22 | ))}
23 |
24 | );
25 | };
26 |
--------------------------------------------------------------------------------
/client/app/components/Story/StoryName.jsx:
--------------------------------------------------------------------------------
1 | // @flow
2 | import React from 'react';
3 | import type { Node } from 'react';
4 | import css from './Story.scss';
5 |
6 | export type Props = {
7 | name: string,
8 | link: ?string,
9 | onClick?: Function,
10 | };
11 |
12 | export const StoryName = ({ name, link, onClick }: Props): Node => {
13 | if (link) {
14 | return (
15 |
16 | {name}
17 |
18 | );
19 | }
20 | if (onClick) {
21 | return (
22 |
25 | );
26 | }
27 | return {name};
28 | };
29 |
--------------------------------------------------------------------------------
/client/app/components/Story/__tests__/StoryBy.spec.jsx:
--------------------------------------------------------------------------------
1 | // @flow
2 | import { render, screen } from '@testing-library/react';
3 | import React from 'react';
4 | import { StoryBy } from 'components/Story/StoryBy';
5 |
6 | describe('StoryBy', () => {
7 | const { getByText } = screen;
8 |
9 | describe('has no options', () => {
10 | it('renders correctly', () => {
11 | render();
12 | expect(getByText('Some author')).toBeInTheDocument();
13 | });
14 | });
15 | describe('has all options', () => {
16 | it('renders correctly', () => {
17 | render();
18 | expect(getByText('Some author')).toBeInTheDocument();
19 | });
20 | });
21 | });
22 |
--------------------------------------------------------------------------------
/client/app/components/Story/__tests__/StoryCategories.spec.jsx:
--------------------------------------------------------------------------------
1 | // @flow
2 | import { render, screen } from '@testing-library/react';
3 | import React from 'react';
4 | import { StoryCategories } from 'components/Story/StoryCategories';
5 |
6 | describe('StoryCategories', () => {
7 | const { getByText } = screen;
8 |
9 | it('renders correctly', () => {
10 | render(
11 | ,
12 | );
13 | expect(getByText('Family')).toBeInTheDocument();
14 | });
15 | });
16 |
--------------------------------------------------------------------------------
/client/app/components/Story/__tests__/StoryDate.spec.jsx:
--------------------------------------------------------------------------------
1 | // @flow
2 | import { render, screen } from '@testing-library/react';
3 | import React from 'react';
4 | import { StoryDate } from 'components/Story/StoryDate';
5 |
6 | describe('StoryDate', () => {
7 | const { getByText } = screen;
8 |
9 | it('renders correctly', () => {
10 | render();
11 | expect(getByText('Created 2 Days ago')).toBeInTheDocument();
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/client/app/components/Story/__tests__/StoryDraft.spec.jsx:
--------------------------------------------------------------------------------
1 | // @flow
2 | import { render, screen } from '@testing-library/react';
3 | import React from 'react';
4 | import { StoryDraft } from 'components/Story/StoryDraft';
5 |
6 | describe('StoryDraft', () => {
7 | const { getByText } = screen;
8 |
9 | it('renders correctly', () => {
10 | render();
11 | expect(getByText('DRAFT')).toBeInTheDocument();
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/client/app/components/Story/__tests__/StoryMoods.spec.jsx:
--------------------------------------------------------------------------------
1 | // @flow
2 | import { render, screen } from '@testing-library/react';
3 | import React from 'react';
4 | import { StoryMoods } from 'components/Story/StoryMoods';
5 |
6 | describe('StoryMoods', () => {
7 | const { getByText } = screen;
8 |
9 | it('renders correctly', () => {
10 | render();
11 | expect(getByText('Nervous')).toBeInTheDocument();
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/client/app/components/Story/__tests__/StoryName.spec.jsx:
--------------------------------------------------------------------------------
1 | // @flow
2 | import { render, screen } from '@testing-library/react';
3 | import React from 'react';
4 | import { StoryName } from 'components/Story/StoryName';
5 |
6 | describe('StoryName', () => {
7 | const { getByText } = screen;
8 |
9 | it('renders correctly', () => {
10 | render();
11 | expect(getByText('Real Moment')).toBeInTheDocument();
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/client/app/components/Toast/Toast.scss:
--------------------------------------------------------------------------------
1 | @import "~styles/_global.scss";
2 |
3 | .toast {
4 | display: flex;
5 | justify-content: space-between;
6 | width: fit-content;
7 | margin: 0 auto;
8 |
9 | button {
10 | background: transparent;
11 | color: $white;
12 | opacity: 1;
13 | border: none;
14 |
15 | &:hover {
16 | border: none;
17 | opacity: 0.8;
18 | }
19 | }
20 | }
21 |
22 | .toastElementHidden {
23 | visibility: hidden;
24 | }
25 |
26 | .toastElementVisible {
27 | visibility: visible;
28 | }
29 |
--------------------------------------------------------------------------------
/client/app/hooks/index.js:
--------------------------------------------------------------------------------
1 | export { useFocusTrap } from './useFocusTrap';
2 |
--------------------------------------------------------------------------------
/client/app/libs/history.js:
--------------------------------------------------------------------------------
1 | import { createBrowserHistory } from 'history';
2 |
3 | export default createBrowserHistory();
4 |
--------------------------------------------------------------------------------
/client/app/pages/MomentTemplates/MomentTemplates.scss:
--------------------------------------------------------------------------------
1 | @import '~styles/_global.scss';
2 |
3 | .newTemplate {
4 | @media screen and (max-width: $small) {
5 | width: 100%;
6 | }
7 |
8 | button {
9 | font-weight: bold;
10 |
11 | @media screen and (max-width: $small) {
12 | width: inherit;
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/client/app/pages/MomentTemplates/MomentTemplatesContext.jsx:
--------------------------------------------------------------------------------
1 | // @flow
2 | import { createContext } from 'react';
3 |
4 | const TemplatesContext: Object = createContext