diff --git a/.gitignore b/.gitignore index 5ea0b7076..1bc7687ee 100644 --- a/.gitignore +++ b/.gitignore @@ -79,4 +79,4 @@ vendor .venv -staff-search \ No newline at end of file +staff-search.worktrees/ diff --git a/app/assets/stylesheets/pages/_hardware_funding.scss b/app/assets/stylesheets/pages/_hardware_funding.scss index 2bce72668..524bbfb16 100644 --- a/app/assets/stylesheets/pages/_hardware_funding.scss +++ b/app/assets/stylesheets/pages/_hardware_funding.scss @@ -24,10 +24,16 @@ $outpost-teal: #34e0ba; color: #fff; font-weight: 800; - &:hover, - &:focus-visible { + &:hover:not(:disabled), + &:focus-visible:not(:disabled) { filter: brightness(1.05); } + + &:disabled { + background: rgba($outpost-ink, 0.15); + color: rgba($outpost-ink, 0.35); + cursor: not-allowed; + } } .ship-modal__btn--secondary { @@ -37,6 +43,67 @@ $outpost-teal: #34e0ba; } } +// "Do you need funding?" question step +.funding-modal__question-heading { + margin: 0 0 1rem; + font-size: 1.1rem; + font-weight: 800; + text-align: center; + color: $outpost-ink; +} + +.funding-modal__question-btns { + display: flex; + flex-direction: column; + gap: 0.6rem; + margin-bottom: 1rem; +} + +.funding-modal__question-btn { + display: flex; + align-items: center; + justify-content: center; + padding: 0.75rem 1rem; + border-radius: 12px; + font: inherit; + font-weight: 700; + font-size: 1rem; + cursor: pointer; + transition: filter 0.12s ease; + + &:hover { + filter: brightness(1.06); + } + + &--yes { + background: linear-gradient(180deg, $outpost-gold, $outpost-orange); + border: none; + color: #fff; + } + + &--no { + background: rgba($outpost-ink, 0.08); + border: 2px solid rgba($outpost-ink, 0.2); + color: $outpost-ink; + } +} + +.funding-modal__question-cancel { + display: flex; + justify-content: center; +} + +.funding-modal__no-funding-note { + margin: 0 0 1rem; + padding: 0.65rem 0.85rem; + border-radius: 10px; + background: color-mix(in srgb, $outpost-teal 22%, #fff); + border: 1px solid color-mix(in srgb, $outpost-teal 55%, #fff); + font-size: 0.95rem; + color: #0c6b58; + line-height: 1.45; +} + .funding-modal__header { display: flex; flex-direction: column; @@ -196,16 +263,41 @@ $outpost-teal: #34e0ba; .funding-modal__bom-check { display: flex; - align-items: center; - gap: 0.5rem; + align-items: flex-start; + gap: 0.6rem; margin-bottom: 1rem; - font-weight: 600; + padding: 0.65rem 0.75rem; + border: 2px solid rgba($outpost-ink, 0.2); + border-radius: 10px; + background: rgba($outpost-ink, 0.04); font-size: 0.9rem; color: $outpost-ink; cursor: pointer; + transition: + border-color 0.12s ease, + background 0.12s ease; + + &:has(input:checked) { + border-color: $outpost-orange; + background: color-mix(in srgb, $outpost-orange 8%, #fff); + } + + &--required { + border-color: rgba($outpost-orange, 0.6); + background: color-mix(in srgb, $outpost-orange 5%, #fff); + } input[type="checkbox"] { + flex: 0 0 auto; + margin-top: 2px; + width: 1.1rem; + height: 1.1rem; accent-color: $outpost-orange; + cursor: pointer; + } + + strong { + color: $outpost-orange; } code { @@ -216,6 +308,11 @@ $outpost-teal: #34e0ba; } } +// Hide the "up to $X" funding max when user selected the no-funding path +.funding-modal__tiers--hide-max .funding-tier__max { + display: none; +} + // Inline tier-max validation error (shown on cream — red reads fine). .funding-request__error { margin: 0 0 1rem; diff --git a/app/assets/stylesheets/pages/projects/_show.scss b/app/assets/stylesheets/pages/projects/_show.scss index 483159d8e..374207b2f 100644 --- a/app/assets/stylesheets/pages/projects/_show.scss +++ b/app/assets/stylesheets/pages/projects/_show.scss @@ -206,6 +206,18 @@ turbo-frame#project_hero { background: var(--color-brand-orange-soft); color: var(--color-brand-orange); } + + &--design { + background: rgba(#ebb7ff, 0.15); + color: #ebb7ff; + border: 1px solid rgba(#ebb7ff, 0.35); + } + + &--build { + background: rgba(#81ffff, 0.12); + color: #81ffff; + border: 1px solid rgba(#81ffff, 0.3); + } } .project-show__title-input { diff --git a/app/controllers/projects/funding_requests_controller.rb b/app/controllers/projects/funding_requests_controller.rb index b554018f4..122afe6a1 100644 --- a/app/controllers/projects/funding_requests_controller.rb +++ b/app/controllers/projects/funding_requests_controller.rb @@ -16,9 +16,9 @@ def create track_event "funding_requested", { project_id: @project.id, complexity_tier: params[:complexity_tier] } redirect_to project_path(@project), - notice: "Funding request submitted! We'll review your design and get back to you." + notice: "Design submitted for review! We'll get back to you soon." rescue ActiveRecord::RecordNotUnique - redirect_to project_path(@project), alert: "You already have a funding request under review." + redirect_to project_path(@project), alert: "You already have a design review in progress." rescue ActiveRecord::RecordInvalid => e redirect_back fallback_location: project_path(@project), alert: e.record.errors.full_messages.to_sentence diff --git a/app/javascript/controllers/project_builder_controller.js b/app/javascript/controllers/project_builder_controller.js index 68d55c40f..109be4fff 100644 --- a/app/javascript/controllers/project_builder_controller.js +++ b/app/javascript/controllers/project_builder_controller.js @@ -1,10 +1,8 @@ import { Controller } from "@hotwired/stimulus"; // Reveals the Design/Build stage chooser on /projects/new when the user clicks -// "Blank new hardware project +". Software projects submit immediately; hardware -// projects pick a stage first. The collapsed chooser is marked inert so its -// controls drop out of the tab order and the a11y tree; a CSS grid-rows -// transition animates the visual reveal. +// "New hardware project +". The collapsed chooser is marked inert so its +// controls drop out of the tab order; a CSS grid-rows transition animates the reveal. export default class extends Controller { static targets = ["chooser", "hardwareBtn"]; diff --git a/app/models/certification/funding_request.rb b/app/models/certification/funding_request.rb index c8bb34580..217754948 100644 --- a/app/models/certification/funding_request.rb +++ b/app/models/certification/funding_request.rb @@ -92,7 +92,7 @@ def self.tier_discount_summary end validates :complexity_tier, inclusion: { in: TIER_MAX_CENTS.keys } - validates :requested_amount_cents, numericality: { only_integer: true, greater_than: 0 } + validates :requested_amount_cents, numericality: { only_integer: true, greater_than_or_equal_to: 0 } validates :approved_amount_cents, numericality: { only_integer: true, greater_than_or_equal_to: 0 }, allow_nil: true validates :feedback, length: { maximum: 10_000 }, allow_blank: true @@ -296,6 +296,7 @@ def accrue_discount_for_owner! def issue_hcb_grant! return if hcb_grant_hashid.present? + return if final_amount_cents.to_i == 0 owner = project.memberships.owner.first&.user || user grant = HCBService.create_card_grant( @@ -317,9 +318,14 @@ def notify_owner! case status.to_sym when :approved - owner.dm_user("Your hardware project '#{project.title}' was approved for $#{final_amount_dollars} in funding! It's switched to the build phase. Log your build hours with a timelapse and ship when you're ready.") + msg = if final_amount_cents.to_i > 0 + "Your design review for '#{project.title}' was approved — you've been granted $#{final_amount_dollars} to buy your parts! Your project is now in the build phase. Log your build hours and ship when you're ready." + else + "Your design review for '#{project.title}' was approved! Your project is now in the build phase. Log your build hours and ship when you're ready." + end + owner.dm_user(msg) when :returned - msg = "Your funding request for '#{project.title}' needs changes before it can be approved." + msg = "Your design review for '#{project.title}' needs changes before it can be approved." msg += "\n\n#{feedback}" if feedback.present? owner.dm_user(msg) end diff --git a/app/views/projects/new.html.erb b/app/views/projects/new.html.erb index 1b1b6e573..6c150c5bd 100644 --- a/app/views/projects/new.html.erb +++ b/app/views/projects/new.html.erb @@ -109,9 +109,9 @@ <%= hidden_field_tag "project[title]", "Untitled" %> <%= hidden_field_tag "project[hardware_stage]", "design" %> <% end %> @@ -119,9 +119,9 @@ <%= hidden_field_tag "project[title]", "Untitled" %> <%= hidden_field_tag "project[hardware_stage]", "build" %> <% end %> diff --git a/app/views/projects/show.html.erb b/app/views/projects/show.html.erb index bd0ca1af1..4337127b3 100644 --- a/app/views/projects/show.html.erb +++ b/app/views/projects/show.html.erb @@ -169,17 +169,17 @@