diff --git a/app/assets/stylesheets/pages/_project_setup.scss b/app/assets/stylesheets/pages/_project_setup.scss index 10d1a8246..47c7d605d 100644 --- a/app/assets/stylesheets/pages/_project_setup.scss +++ b/app/assets/stylesheets/pages/_project_setup.scss @@ -78,6 +78,57 @@ &__submit { margin-top: 0.75rem; } + + &__funding { + border: none; + margin: 0.5rem 0 0; + padding: 0; + width: 100%; + } + + &__funding-legend { + color: var(--color-brand-off-white); + font-family: var(--font-family-text); + font-size: 1.1rem; + font-weight: 700; + margin-bottom: 0.75rem; + } + + &__funding-options { + display: flex; + flex-direction: column; + gap: 0.6rem; + } + + &__funding-option { + align-items: center; + background: rgba(8, 6, 31, 0.75); + border: 2px solid var(--color-space-border); + border-radius: 0.5rem; + cursor: pointer; + display: flex; + gap: 0.75rem; + padding: 0.75rem 1rem; + transition: border-color 180ms ease; + + &:hover, + &:has(:checked) { + border-color: var(--color-brand-lilac); + } + } + + &__funding-radio { + accent-color: var(--color-brand-lilac); + flex-shrink: 0; + height: 1.1rem; + width: 1.1rem; + } + + &__funding-label { + color: var(--color-brand-off-white); + font-family: var(--font-family-text); + font-size: 1rem; + } } // Missions step — grid of mission cards + escape hatch. diff --git a/app/components/projects/setup/progress_bar_component.rb b/app/components/projects/setup/progress_bar_component.rb index f788d1c2e..dcff09ebe 100644 --- a/app/components/projects/setup/progress_bar_component.rb +++ b/app/components/projects/setup/progress_bar_component.rb @@ -6,10 +6,11 @@ class ProgressBarComponent < ViewComponent::Base # Per-action mapping into the visible 3-phase progress. ACTION_TO_STEP = { - idea: :idea, - name: :details, - missions: :details, - link: :link + idea: :idea, + project_type: :idea, + name: :details, + missions: :details, + link: :link }.freeze attr_reader :action @@ -46,6 +47,8 @@ def back_path case action when :idea, :link append_back_param(helpers.back_path) + when :project_type + helpers.projects_setup_path(back: 1) when :name, :missions helpers.projects_setup_path(back: 1) end diff --git a/app/controllers/projects/setup_controller.rb b/app/controllers/projects/setup_controller.rb index f89a9975f..afda34814 100644 --- a/app/controllers/projects/setup_controller.rb +++ b/app/controllers/projects/setup_controller.rb @@ -25,7 +25,7 @@ def submit_idea case params[:idea].to_s when "yes" track_event "project_setup_started", { has_idea: true } - redirect_to projects_setup_name_path + redirect_to projects_setup_project_type_path when "no" track_event "project_setup_started", { has_idea: false } redirect_to projects_setup_missions_path @@ -34,8 +34,28 @@ def submit_idea end end + def project_type + authorize :project_setup + end + + def submit_project_type + authorize :project_setup + + case params[:project_type].to_s + when "software" + session[:setup_is_hardware] = false + redirect_to projects_setup_name_path + when "hardware" + session[:setup_is_hardware] = true + redirect_to projects_setup_name_path + else + redirect_to projects_setup_project_type_path, alert: "Please pick one." + end + end + def name authorize :project_setup + @is_hardware = session[:setup_is_hardware] == true end MAX_TITLE_LENGTH = 120 @@ -58,7 +78,11 @@ def submit_name end project = find_or_create_setup_project! - project.update!(title: title, description: description.presence) + is_hardware = session.delete(:setup_is_hardware) + hardware_stage = if is_hardware + params[:needs_funding].to_s == "no" ? "build" : "design" + end + project.update!(title: title, description: description.presence, hardware_stage: hardware_stage) redirect_to next_gate_after_details_path end diff --git a/app/policies/project_setup_policy.rb b/app/policies/project_setup_policy.rb index 9a72cf579..8a22c71cd 100644 --- a/app/policies/project_setup_policy.rb +++ b/app/policies/project_setup_policy.rb @@ -1,6 +1,8 @@ class ProjectSetupPolicy < ApplicationPolicy def idea? = signed_in_any? def submit_idea? = signed_in_any? + def project_type? = signed_in_any? + def submit_project_type? = signed_in_any? def name? = signed_in_any? def submit_name? = signed_in_any? def missions? = signed_in_any? diff --git a/app/views/projects/setup/name.html.erb b/app/views/projects/setup/name.html.erb index a189b80c3..8a96a027d 100644 --- a/app/views/projects/setup/name.html.erb +++ b/app/views/projects/setup/name.html.erb @@ -27,6 +27,22 @@ maxlength: Projects::SetupController::MAX_DESCRIPTION_LENGTH, class: "project-setup-name__textarea" %> + <% if @is_hardware %> +
+ Do you need funding to buy parts? +
+ + +
+
+ <% end %> + <%= render SpecialActionButtonComponent.new( text: "Continue", type: :submit, diff --git a/app/views/projects/setup/project_type.html.erb b/app/views/projects/setup/project_type.html.erb new file mode 100644 index 000000000..165016494 --- /dev/null +++ b/app/views/projects/setup/project_type.html.erb @@ -0,0 +1,22 @@ +<% content_for :title, "What type of project?" %> +
+ <%= render Projects::Setup::ProgressBarComponent.new(action: :project_type) %> + +
+

tell us more ✦

+

Is it a software project
or a hardware project?

+ + <%= form_with url: projects_setup_submit_project_type_path, method: :post, + class: "project-setup-idea__form" do %> +
+ <%= render Onboarding::ChoiceCardComponent.new(name: "project_type", value: "software", variant: :pair) do %> + Software — an app, website, game, or bot. + <% end %> + <%= render Onboarding::ChoiceCardComponent.new(name: "project_type", value: "hardware", variant: :pair) do %> + Hardware — something I build physically. + <% end %> +
+ <% end %> +
+
diff --git a/app/views/projects/show.html.erb b/app/views/projects/show.html.erb index 817f0add8..29d5e2ad6 100644 --- a/app/views/projects/show.html.erb +++ b/app/views/projects/show.html.erb @@ -359,7 +359,7 @@ <% end %> <% unless @hackatime_linked %> - @@ -655,7 +655,7 @@ project: @project, disabled_message: "Link your Hackatime account to start recording" %> <% end %> - <%= button_to "/auth/hackatime", + <%= button_to "/auth/hackatime#{"?skip_setup_flow" if @project.hardware?}", method: :post, params: { origin: request.fullpath }, class: "action-btn action-btn--large action-btn--primary project-show__hackatime-cta", diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index 5bb858e83..81c5d68d4 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -46,6 +46,13 @@ def callback_url { name: :hackatime, scope: "profile read", + setup: lambda { |env| + request = Rack::Request.new(env) + if request.params.key?("skip_setup_flow") + env["omniauth.strategy"].options[:authorize_params] ||= {} + env["omniauth.strategy"].options[:authorize_params][:skip_setup_flow] = request.params["skip_setup_flow"] + end + }, client_options: { site: "https://hackatime.hackclub.com", authorize_url: "/oauth/authorize", diff --git a/config/routes.rb b/config/routes.rb index 3ee73737f..d7907e332 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -852,6 +852,8 @@ namespace :projects do get "setup", to: "setup#idea", as: :setup post "setup/idea", to: "setup#submit_idea", as: :setup_submit_idea + get "setup/project_type", to: "setup#project_type", as: :setup_project_type + post "setup/project_type", to: "setup#submit_project_type", as: :setup_submit_project_type get "setup/name", to: "setup#name", as: :setup_name post "setup/name", to: "setup#submit_name", as: :setup_submit_name get "setup/missions", to: "setup#missions", as: :setup_missions