Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,4 @@ vendor

.venv

staff-search
staff-search.worktrees/
107 changes: 102 additions & 5 deletions app/assets/stylesheets/pages/_hardware_funding.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;
Expand Down Expand Up @@ -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 {
Expand All @@ -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;
Expand Down
12 changes: 12 additions & 0 deletions app/assets/stylesheets/pages/projects/_show.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/projects/funding_requests_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 2 additions & 4 deletions app/javascript/controllers/project_builder_controller.js
Original file line number Diff line number Diff line change
@@ -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"];

Expand Down
12 changes: 9 additions & 3 deletions app/models/certification/funding_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand All @@ -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
Expand Down
12 changes: 6 additions & 6 deletions app/views/projects/new.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -109,19 +109,19 @@
<%= hidden_field_tag "project[title]", "Untitled" %>
<%= hidden_field_tag "project[hardware_stage]", "design" %>
<button type="submit" class="project-creation__stage-option">
<span class="project-creation__stage-label">I need Funding</span>
<span class="project-creation__stage-title">I need funding to buy parts for my project</span>
<span class="project-creation__stage-subtext">Submit your design and we'll fund your build</span>
<span class="project-creation__stage-label">Design Stage</span>
<span class="project-creation__stage-title">I'm still working on my design</span>
<span class="project-creation__stage-subtext">Post devlogs and submit your design for review when it's ready</span>
</button>
<% end %>

<%= form_with url: projects_path, method: :post, data: { turbo_frame: "_top" }, class: "project-creation__stage-form" do %>
<%= hidden_field_tag "project[title]", "Untitled" %>
<%= hidden_field_tag "project[hardware_stage]", "build" %>
<button type="submit" class="project-creation__stage-option">
<span class="project-creation__stage-label">I don't need Funding</span>
<span class="project-creation__stage-title">I don't need funding for my project</span>
<span class="project-creation__stage-subtext">I already have my parts and am ready to start building</span>
<span class="project-creation__stage-label">Build Stage</span>
<span class="project-creation__stage-title">I have my parts and I'm ready to build</span>
<span class="project-creation__stage-subtext">Start logging build hours right away</span>
</button>
<% end %>
</div>
Expand Down
Loading