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: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,5 @@ CLAUDE.md

/app/assets/builds/*
!/app/assets/builds/.keep
.cursorindexingignore
.specstory/
7 changes: 7 additions & 0 deletions app/assets/stylesheets/components/_account.scss
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,13 @@
}
}

.c-account__input--readonly-field {
border: 1px solid #d1d5db !important;
background-color: #f9fafb;
color: #6b7280;
cursor: not-allowed;
}

.c-account__checkbox {
gap: 16px;

Expand Down
7 changes: 7 additions & 0 deletions app/assets/stylesheets/components/_btn.scss
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,11 @@ table {
font-size: rem(15px);
margin: 2.5rem 0 1.5rem 0;
}
}

.c-btn--disabled,
.c-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
pointer-events: none;
}
42 changes: 42 additions & 0 deletions app/assets/stylesheets/components/_notifications.scss
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,46 @@
border-bottom: 1px solid $grey-200-color;
}
}
}

.c-notification__empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: rem(60px) rem(20px);
text-align: center;
min-height: rem(300px);
}

.c-notification__empty-icon {
color: #94a3b8;
margin-bottom: rem(24px);
opacity: 0.8;
}

.c-notification__empty-icon--read {
color: #cbd5e1;
width: 48px;
height: 48px;
}

.c-notification__empty-title {
font-size: rem(18px);
font-weight: 600;
color: #64748b;
margin: 0 0 rem(8px) 0;
line-height: 1.4;
}

.c-notification__empty-description {
font-size: rem(14px);
color: #94a3b8;
margin: 0;
line-height: 1.5;
}

.c-notification__empty-state--read {
min-height: rem(200px);
padding: rem(40px) rem(20px);
}
4 changes: 2 additions & 2 deletions app/components/common/auction_type_icon/component.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<% if english? %>
<span class="o-io-icon auction_platform"></span><span class="u-hidden">IO</span>
<span class="o-io-icon auction_platform" title="<%= t('auctions.english_auction_tooltip') %>"></span><span class="u-hidden">IO</span>
<% else %>
<span class="o-po-icon auction_platform"></span><span class="u-hidden">PO</span>
<span class="o-po-icon auction_platform" title="<%= t('auctions.blind_auction_tooltip') %>"></span><span class="u-hidden">PO</span>
<% end %>
2 changes: 1 addition & 1 deletion app/components/common/footer/component.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<div class="c-footer__highlight__grid">
<h3 class="c-footer__highlight__title">
<div>
<%= t('common.footer.copyright') %>
<%= t('common.footer.copyright', year: Date.today.year) %>
</div>
</h3>
<div class="c-footer__highlight__info">
Expand Down
2 changes: 1 addition & 1 deletion app/components/common/table/component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def currently_sorted?(column)
end

def next_direction(column)
return unless currently_sorted?(column)
return 'asc' unless currently_sorted?(column)

params[:sort_direction] == 'asc' ? 'desc' : 'asc'
end
Expand Down
2 changes: 1 addition & 1 deletion app/components/modals/winner_domain/component.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<span class="o-po-icon o-io-icon--bg-orange"></span>
</div>
<div class="c-modal__header__desc">
<span><%= t('results.status') %></span> <span class="c-badge c-badge--yellow"><%= @result.status.humanize %></span>
<span><%= t('results.status') %></span> <span class="c-badge c-badge--yellow"><%= Result.human_attribute_name("status/#{@result.status}") %></span>
</div>
</div>
<div class="c-modal__main">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@
<%= component 'common/table', header_collection: bidder_table_headers, options: { class: '' } do %>
<%= tag.tbody do %>
<% @offer.auction.offers.order(updated_at: :desc).each do |offer| %>
<tr class="offers-table-row">
<tr class="offers-table-row" data-controller="auction-timezone" data-auction-timezone-end-time-value="<%= offer.updated_at.iso8601 %>">
<td style="<%= offer&.billing_profile&.user_id == current_user.id ? 'color: green;' : '' %>">
<%= offer&.billing_profile&.user_id == current_user.id ? "#{offer.username} (You)" : offer.username %>
</td>
<td><%= t('offers.price_in_currency', price: offer.price) %></td>
<td><%= I18n.l(offer.updated_at) %></td>
<td><span data-auction-timezone-target="endtime"><%= offer.updated_at %></span></td>
</tr>
<% end %>
<% end %>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def initialize(offer:)

def overview_table_headers
[{ column: nil, caption: t('auctions.domain_name'), options: { class: '' } },
{ column: nil, caption: t('auctions.ends_at'), options: { class: '' } },
{ column: nil, caption: t('auctions.ended_at'), options: { class: '' } },
{ column: nil, caption: t('offers.price'), options: { class: '' } }]
end

Expand Down
9 changes: 6 additions & 3 deletions app/components/pages/offers/offers_table/component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ def initialize(offers:)
end

def header_collection
[{ column: 'auctions.domain_name', caption: t('auctions.domain_name'), options: { class: 'sorting' } },
{ column: 'auctions.platform', caption: t('auctions.type'), options: { class: 'sorting' } },
[{ column: 'auctions.domain_name', caption: t('auctions.domain_name'),
options: { class: 'sorting' } },
{ column: 'auctions.platform', caption: t('auctions.type'),
options: { class: 'sorting' } },
{ column: nil, caption: t('offers.show.your_last_offer'), options: { class: '' } },
{ column: 'offers.created_at', caption: t('offers.created_at'), options: { class: 'sorting' } },
{ column: 'offers.created_at', caption: t('offers.created_at'),
options: { class: 'sorting' } },
{ column: 'auctions.ends_at', caption: t('auctions.ends_at'),
options: { class: 'sorting' } },
{ column: nil, caption: t('result_name'), options: {} },
Expand Down
6 changes: 4 additions & 2 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,10 @@ def clear_flash
protected

def authenticate_user!
Rails.logger.debug "=== authenticate_user! called, user_signed_in?: #{user_signed_in?}"
return if user_signed_in?

Rails.logger.debug "=== User NOT signed in, redirecting..."
store_location_for(:user, request.fullpath) if request.get? || request.head?
store_location_for(:user, request.referer) unless request.get? || request.head?

Expand All @@ -90,9 +92,9 @@ def authenticate_user!
flash[:alert] = t('devise.failure.unauthenticated')

if turbo_frame_request?
render turbo_stream: turbo_stream.action(:redirect, root_path)
render turbo_stream: turbo_stream.action(:redirect, root_path) and return false
else
redirect_to new_user_session_path
redirect_to new_user_session_path and return false
end
end

Expand Down
7 changes: 4 additions & 3 deletions app/controllers/autobider_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ class AutobiderController < ApplicationController
before_action :authenticate_user!
before_action :set_auction, only: %i[new edit update create]
before_action :allow_any_action_with_autobider

include RecaptchaValidatable
recaptcha_action 'autobidder'

Expand All @@ -25,8 +25,9 @@ def update

render turbo_stream: [
turbo_stream.replace('flash', partial: 'common/flash', locals: { flash: }),
turbo_stream.update('autobider-status', html: @autobider.enable ? I18n.t('english_offers.form.yep') : I18n.t('english_offers.form.nope'))
]
turbo_stream.update('autobider-status',
html: @autobider.enable ? I18n.t('english_offers.form.yep') : I18n.t('english_offers.form.nope'))
]
end

def edit
Expand Down
5 changes: 3 additions & 2 deletions app/controllers/english_offers_controller.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# frozen_string_literal: true

class EnglishOffersController < ApplicationController
before_action :set_offer, only: %i[show edit update]

include BeforeRender
include Offerable

before_action :set_offer, only: %i[show edit update]

protect_from_forgery with: :null_session

# order is important
Expand Down
3 changes: 3 additions & 0 deletions app/javascript/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,6 @@ application.register("slashed-zero", SlashedZeroController);

import OfferPriceValidatorController from "./offer_price_validator_controller";
application.register("offer-price-validator", OfferPriceValidatorController);

import WishlistController from "./wishlist_controller";
application.register("wishlist", WishlistController);
27 changes: 27 additions & 0 deletions app/javascript/controllers/wishlist_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Controller } from "@hotwired/stimulus"

// Connects to data-controller="wishlist"
export default class extends Controller {
static targets = ["input", "submit"]

connect() {
// Check initial state on connect
this.toggleSubmitButton()
}

domainCheck() {
this.toggleSubmitButton()
}

toggleSubmitButton() {
const inputValue = this.inputTarget.value.trim()

if (inputValue.length > 0) {
this.submitTarget.disabled = false
this.submitTarget.classList.remove('c-btn--disabled')
} else {
this.submitTarget.disabled = true
this.submitTarget.classList.add('c-btn--disabled')
}
}
}
2 changes: 1 addition & 1 deletion app/views/admin/auctions/_deposit_participants.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
<% end %>
<% end %>

<%= turbo_frame_tag "results" do %>
<%= turbo_frame_tag "results", autoscroll: true, data: { autoscroll_block: "start", autoscroll_behavior: "smooth" } do %>
<div class="column" style="margin-top:10px; text-align: center;">
<% if @pagy.pages > 1 %>
<div class="footer">
Expand Down
2 changes: 1 addition & 1 deletion app/views/admin/auctions/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@
{ column: 'requirement_deposit_in_cents', caption: t('auctions.auctions'), options: { class: 'sorting' } },
{ column: 'enable_deposit', caption: t('auctions.enable_deposit'), options: { class: 'sorting' } }] %>
<!-- In the Stimulus controller, I use the Turbo class with frame parameters named 'results' for table sorting. This means that rendering the table with the new sort order should occur within the scope of the turbo_frame_tag with the name "results". For it to work correctly, it's necessary to wrap the table content within this turbo_frame_tag with "results" name. The name "results" is assigned as a value for the orderable Stimulus controller in the table component. -->
<%= turbo_frame_tag "results" do %>
<%= turbo_frame_tag "results", autoscroll: true, data: { autoscroll_block: "start", autoscroll_behavior: "smooth" } do %>
<!-- Options attributes are used as table attributes -->
<%= component 'common/table', header_collection:, options: { class: 'js-table-dt dataTable no-footer' } do %>
<!-- "The body of the table also needs to be in the component block, so the component wraps it with the necessary tags." -->
Expand Down
2 changes: 1 addition & 1 deletion app/views/auctions/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
{ column: nil, caption: t('auctions.offer_actions'), options: { class: 'u-text-left u-text-center-l' } }] %>

<!-- In the Stimulus controller, I use the Turbo class with frame parameters named 'results' for table sorting. This means that rendering the table with the new sort order should occur within the scope of the turbo_frame_tag with the name "results". For it to work correctly, it's necessary to wrap the table content within this turbo_frame_tag with "results" name. The name "results" is assigned as a value for the orderable Stimulus controller in the table component. -->
<%= turbo_frame_tag "results" do %>
<%= turbo_frame_tag "results", autoscroll: true, data: { autoscroll_block: "start", autoscroll_behavior: "smooth" } do %>

<!-- Options attributes are used as table attributes -->
<%= component 'common/table', header_collection:, options: { class: 'js-table-dt dataTable no-footer' } do %>
Expand Down
14 changes: 7 additions & 7 deletions app/views/billing_profiles/_billing_info.html.erb
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<%= turbo_frame_tag dom_id(billing_profile) do %>
<div class="o-card">
<div class="c-account__form">
<div class="c-account__title-wrapper c-account__input c-account__input--editable c-account__input-title u-flex u-content-sp">
<input type="text" class="o-card__title c-account__title" placeholder="" value="<%= billing_profile.name %>" readonly>
<div class="c-account__title-wrapper c-account__input c-account__input--editable c-account__input-title u-flex u-content-sp u-align-center">
<input type="text" class="o-card__title c-account__title" placeholder="" value="<%= billing_profile.name.presence || t('billing_profiles.not_filled') %>" readonly>
<div class="c-account_editicons u-flex u-align-center u-content-end">

<%= button_to billing_profile_path(uuid: billing_profile.uuid), method: :delete, data: {turbo_method: :delete, turbo_confirm: "Are you sure to delete "}, target: '_top', style: 'background: transparent; border: none;' do %>
Expand All @@ -15,25 +15,25 @@

<div class="c-account__input c-account__input--editable u-mb-20">
<label for="input1"><%= t('billing_profiles.vat_code') %></label>
<input id="input1" type="text" placeholder="" value="<%= billing_profile.vat_code %>" readonly/>
<input id="input1" class="c-account__input--readonly-field" type="text" placeholder="" value="<%= billing_profile.vat_code.presence || t('billing_profiles.not_filled') %>" readonly/>
</div>

<div class="c-account__input-wrapper u-flex u-align-start u-content-start">
<div class="c-account__input c-account__input--editable u-mb-20">
<label for="input2"><%= t('billing_profiles.street') %></label>
<input id="input2" type="text" placeholder="" value="<%= billing_profile.street %>" readonly/>
<input id="input2" class="c-account__input--readonly-field" type="text" placeholder="" value="<%= billing_profile.street.presence || t('billing_profiles.not_filled') %>" readonly/>
</div>
<div class="c-account__input c-account__input--editable u-mb-20">
<label for="input3"><%= t('billing_profiles.city') %></label>
<input id="input3" type="text" placeholder="" value="<%= billing_profile.city %>" readonly/>
<input id="input3" class="c-account__input--readonly-field" type="text" placeholder="" value="<%= billing_profile.city.presence || t('billing_profiles.not_filled') %>" readonly/>
</div>
<div class="c-account__input c-account__input--editable u-mb-20">
<label for="input4"><%= t('billing_profiles.postal_code') %></label>
<input id="input4" type="text" placeholder="" value="<%= billing_profile.postal_code %>" readonly/>
<input id="input4" class="c-account__input--readonly-field" type="text" placeholder="" value="<%= billing_profile.postal_code.presence || t('billing_profiles.not_filled') %>" readonly/>
</div>
<div class="c-account__input c-account__input--editable u-mb-20">
<label for="input5"><%= t('billing_profiles.country') %></label>
<input id="input4" type="text" placeholder="" value="<%= billing_profile.country_code %>" readonly/>
<input id="input5" class="c-account__input--readonly-field" type="text" placeholder="" value="<%= billing_profile.country_code.presence || t('billing_profiles.not_filled') %>" readonly/>
</div>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion app/views/histories/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
{ column: 'username', caption: t('auctions.offer_owner'), options: { class: "sorting" } }] %>

<!-- In the Stimulus controller, I use the Turbo class with frame parameters named 'results' for table sorting. This means that rendering the table with the new sort order should occur within the scope of the turbo_frame_tag with the name "results". For it to work correctly, it's necessary to wrap the table content within this turbo_frame_tag with "results" name. The name "results" is assigned as a value for the orderable Stimulus controller in the table component. -->
<%= turbo_frame_tag "results" do %>
<%= turbo_frame_tag "results", autoscroll: true, data: { autoscroll_block: "start", autoscroll_behavior: "smooth" } do %>

<!-- Options attributes are used as table attributes -->
<%= component 'common/table', header_collection:, options: { class: 'js-table-dt dataTable no-footer' } do %>
Expand Down
29 changes: 24 additions & 5 deletions app/views/notifications/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

<!-- Unreaded Notifications -->
<div class="o-container">
<div style='display: flex; justify-content: end;'>
<%= component 'common/buttons/button_to', title_caption: t('notifications.read_all'), href: mark_as_read_notifications_path, color: 'orange', options: { method: :patch } %>
</div>
<% if @unread_notifications.present? %>
<div style='display: flex; justify-content: end; margin-bottom: 20px;'>
<%= component 'common/buttons/button_to', title_caption: t('notifications.read_all'), href: mark_as_read_notifications_path, color: 'orange', options: { method: :patch } %>
</div>
<% end %>

<h2><%= t('notifications.unreaded_notifications') %> <sup>(<%= @unread_notifications&.count %>)</sup></h2>
<%= turbo_frame_tag :unread_notifications do %>
Expand All @@ -27,7 +29,17 @@
<%= component 'common/pagy', pagy: @unread_pagy %>
<% else %>
<div class="c-notifications">
<p class="c-notification__empty"><%= t('notifications.no_unread_notifications') %></p>
<div class="c-notification__empty-state">
<svg class="c-notification__empty-icon" xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"></path>
<path d="M13.73 21a2 2 0 0 1-3.46 0"></path>
<path d="M9 8V6a3 3 0 0 1 6 0v2"></path>
<line x1="6" y1="8" x2="18" y2="16"></line>
<line x1="18" y1="8" x2="6" y2="16"></line>
</svg>
<p class="c-notification__empty-title"><%= t('notifications.no_unread_notifications') %></p>
<p class="c-notification__empty-description"><%= t('notifications.all_caught_up') %></p>
</div>
</div>
<% end %>
<% end %>
Expand Down Expand Up @@ -55,7 +67,14 @@
<%= component 'common/pagy', pagy: @read_pagy %>
<% else %>
<div class="c-notifications">
<p class="c-notification__empty"><%= t('notifications.no_read_notifications') %></p>
<div class="c-notification__empty-state c-notification__empty-state--read">
<svg class="c-notification__empty-icon c-notification__empty-icon--read" xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"></path>
<path d="M13.73 21a2 2 0 0 1-3.46 0"></path>
<circle cx="12" cy="12" r="1" fill="currentColor"></circle>
</svg>
<p class="c-notification__empty-title"><%= t('notifications.no_read_notifications') %></p>
</div>
</div>
<% end %>
<% end %>
Expand Down
Loading
Loading