diff --git a/app/assets/stylesheets/application.tailwind.css b/app/assets/stylesheets/application.tailwind.css
index 0822877..95686c4 100644
--- a/app/assets/stylesheets/application.tailwind.css
+++ b/app/assets/stylesheets/application.tailwind.css
@@ -213,7 +213,7 @@
.select,
select {
- @apply block w-full rounded-md border-0 px-3 pl-3 pr-10 text-default ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-brand-600 sm:text-sm sm:leading-6;
+ @apply block w-full rounded-md border-0 px-3 pl-3 pr-10 text-default ring-1 ring-inset ring-subtle focus:ring-2 focus:ring-brand-600 sm:text-sm sm:leading-6;
}
label {
@@ -261,11 +261,11 @@
oijoijoij
} */
.my-react-select-container .my-react-select__control {
- @apply bg-white dark:bg-neutral-700 border-2 border-neutral-300 dark:border-neutral-700 hover:border-neutral-400 dark:hover:border-neutral-500;
+ @apply bg-default border-2 border-subtle hover:border-muted;
}
.my-react-select-container .my-react-select__control--is-focused {
- @apply border-neutral-500 hover:border-neutral-500 dark:border-neutral-400 dark:hover:border-neutral-400 shadow-none;
+ @apply border-subtle hover:border-subtle shadow-none;
}
.my-react-select-container .my-react-select__menu {
diff --git a/app/controllers/playlist_purchases_controller.rb b/app/controllers/playlist_purchases_controller.rb
new file mode 100644
index 0000000..203b1c6
--- /dev/null
+++ b/app/controllers/playlist_purchases_controller.rb
@@ -0,0 +1,107 @@
+class PlaylistPurchasesController < ApplicationController
+ before_action :authenticate_user!
+
+ def new
+ @playlist = Playlist.friendly.find(params[:playlist_id])
+ @payment = Payment.new
+ @payment.assign_attributes(initial_price: @playlist.price)
+ @purchase = current_user.purchases.new
+ end
+
+ def create
+ @playlist = Playlist.friendly.find(params[:playlist_id])
+ @payment = Payment.new
+ @payment.assign_attributes(build_params)
+
+ customer = current_user
+
+ price = @playlist.price
+ price_param = build_params[:price].to_f
+ if @playlist.name_your_price? && price_param && price_param > @playlist.price.to_f
+ price = price_param
+ end
+
+ @purchase = current_user.purchases.new(purchasable: @playlist, price: price)
+
+ @purchase.virtual_purchased = [
+ VirtualPurchasedItem.new({resource: @playlist, quantity: 1})
+ ]
+
+ handle_stripe_session
+ end
+
+ def handle_stripe_session
+ account = @playlist.user.oauth_credentials.find_by(provider: "stripe_connect")
+ Stripe.stripe_account = account.uid unless account.blank?
+
+ ActiveRecord::Base.transaction do
+ @purchase.store_items
+ @purchase.save
+
+ line_items = [{
+ "quantity" => 1,
+ "price_data" => {
+ "unit_amount" => (@purchase.price * 100).to_i,
+ "currency" => "USD",
+ "product_data" => {
+ "name" => @playlist.title,
+ "description" => "#{@playlist.title} from #{@playlist.user.username}"
+ }
+ }
+ }]
+
+ fee_amount = ENV.fetch('PLATFORM_EVENTS_FEE', 3).to_i
+
+ payment_intent_data = {}
+
+ if account
+ payment_intent_data = {
+ application_fee_amount: fee_amount
+ }
+ end
+
+ @session = Stripe::Checkout::Session.create(
+ payment_method_types: ["card"],
+ line_items: line_items,
+ payment_intent_data: payment_intent_data,
+ customer_email: current_user.email,
+ mode: "payment",
+ success_url: success_playlist_playlist_purchase_url(@playlist, @purchase),
+ cancel_url: failure_playlist_playlist_purchase_url(@playlist, @purchase)
+ )
+
+ @purchase.update(
+ checkout_type: "stripe",
+ checkout_id: @session["id"]
+ )
+
+ @payment_url = @session["url"]
+ end
+ end
+
+ def success
+ @playlist = Playlist.friendly.find(params[:playlist_id])
+ @purchase = current_user.purchases.find(params[:id])
+
+ if params[:enc].present?
+ decoded_purchase = Purchase.find_signed(CGI.unescape(params[:enc]))
+ @purchase.complete_purchase! if decoded_purchase.id == @purchase.id
+ end
+
+ render "show"
+ end
+
+ def failure
+ @playlist = Playlist.friendly.find(params[:playlist_id])
+ @purchase = current_user.purchases.find(params[:id])
+ render "show"
+ end
+
+ private
+
+ def build_params
+ params.require(:payment).permit(
+ :include_message, :optional_message, :price
+ )
+ end
+end
diff --git a/app/controllers/playlists_controller.rb b/app/controllers/playlists_controller.rb
index 2018091..e4393e8 100644
--- a/app/controllers/playlists_controller.rb
+++ b/app/controllers/playlists_controller.rb
@@ -70,6 +70,7 @@ def playlist_params
:record_label, :buy_link, :buy_link_title,
:enable_label,
:copyright,
+ :name_your_price,
:attribution, :noncommercial, :non_derivative_works, :copies,
track_playlists_attributes: [
:id,
diff --git a/app/controllers/purchases_controller.rb b/app/controllers/purchases_controller.rb
index 6726c6e..074a581 100644
--- a/app/controllers/purchases_controller.rb
+++ b/app/controllers/purchases_controller.rb
@@ -11,6 +11,39 @@ def tickets
def music
kind = (params[:tab] == "tracks") ? "Track" : "Playlist"
- @collection = current_user.purchases.where(state: "paid", purchasable_type: kind).page
+ type = params[:type] || "paid"
+ @collection = current_user.purchases.where(state: type, purchasable_type: kind).page
+ end
+
+ def download
+ @purchase = Purchase.find(params[:id])
+
+ if @purchase.purchasable.zip.attached?
+ render turbo_stream: turbo_stream.replace(
+ "purchase_#{@purchase.id}_download",
+ partial: 'purchases/download_ready',
+ locals: { purchase: @purchase }
+ )
+ else
+ ZipperJob.perform_later(purchase_id: @purchase.id)
+ render turbo_stream: turbo_stream.replace(
+ "purchase_#{@purchase.id}_download",
+ partial: 'purchases/download_processing',
+ locals: { purchase: @purchase }
+ )
+ end
+ end
+
+ def check_zip_status
+ @purchase = Purchase.find(params[:id])
+ if @purchase.purchasable.zip.attached?
+ render turbo_stream: turbo_stream.replace(
+ "purchase_#{@purchase.id}_download",
+ partial: 'purchases/download_ready',
+ locals: { purchase: @purchase }
+ )
+ else
+ head :no_content
+ end
end
end
diff --git a/app/controllers/track_purchases_controller.rb b/app/controllers/track_purchases_controller.rb
index 6534478..9047923 100644
--- a/app/controllers/track_purchases_controller.rb
+++ b/app/controllers/track_purchases_controller.rb
@@ -56,7 +56,7 @@ def handle_stripe_session
puts line_items
- fee_amount = 3
+ fee_amount = ENV.fetch('PLATFORM_EVENTS_FEE', 3).to_i
payment_intent_data = {}
diff --git a/app/helpers/playlist_purchases_helper.rb b/app/helpers/playlist_purchases_helper.rb
new file mode 100644
index 0000000..f8e2fd9
--- /dev/null
+++ b/app/helpers/playlist_purchases_helper.rb
@@ -0,0 +1,2 @@
+module PlaylistPurchasesHelper
+end
diff --git a/app/helpers/tailwind_form_builder.rb b/app/helpers/tailwind_form_builder.rb
index de21a4c..cefa5e3 100644
--- a/app/helpers/tailwind_form_builder.rb
+++ b/app/helpers/tailwind_form_builder.rb
@@ -151,7 +151,6 @@ def radio_button(method, value, options = {})
end
def check_box(method, options = {}, checked_value = "1", unchecked_value = "0")
- # Conditionally build the label if options[:label] is not false
info = ""
unless options[:label] == false
info = @template.label_tag(
@@ -160,14 +159,22 @@ def check_box(method, options = {}, checked_value = "1", unchecked_value = "0")
) + field_details(method, object, options)
end
- # Merge in default class unless a specific class has been provided in options
options.merge!(class: "self-center mt-1-- mr-2 form-checkbox h-4 w-4 text-indigo-600 transition duration-150 ease-in-out") unless options.key?(:class)
- # Create the checkbox and, conditionally, its label
+ hint = ""
+ if options[:hint].present?
+ hint_text = options[:hint].is_a?(Proc) ? @template.capture(&options[:hint]) : options[:hint]
+ hint = @template.content_tag(:p, hint_text.html_safe, class: "mt-1 text-sm text-gray-500")
+ end
+
@template.tag.div(class: "flex items-center space-x-2") do
- @template.check_box(
+ checkbox = @template.check_box(
@object_name, method, objectify_options(options), checked_value, unchecked_value
- ) + (info.present? ? @template.tag.div(class: "flex-col items-center") { info } : "".html_safe)
+ )
+ label_and_hint = @template.tag.div(class: "flex-col items-center") do
+ (info + hint).html_safe
+ end
+ checkbox + label_and_hint
end
end
diff --git a/app/jobs/zipper_job.rb b/app/jobs/zipper_job.rb
index b084125..4b320b4 100644
--- a/app/jobs/zipper_job.rb
+++ b/app/jobs/zipper_job.rb
@@ -3,8 +3,16 @@
class ZipperJob < ApplicationJob
queue_as :default
- def perform(track_id: nil, playlist_id: nil)
- if track_id
+ def perform(track_id: nil, playlist_id: nil, purchase_id: nil)
+ if purchase_id
+ purchase = Purchase.find(purchase_id)
+ resource = purchase.purchasable
+ if resource.is_a?(Track)
+ track_zip(resource)
+ elsif resource.is_a?(Playlist)
+ playlist_zip(resource)
+ end
+ elsif track_id
track = Track.find_by(id: track_id)
return unless track
track_zip(track)
@@ -52,32 +60,62 @@ def track_zip(record)
Rails.logger.error "Error zipping track #{record.id}: #{e.message}"
end
- def playlist_zip(playlist)
- zipfile_path = Rails.root.join("tmp", "#{playlist.slug}-#{playlist.id}.zip")
-
- Zip::File.open(zipfile_path, Zip::File::CREATE) do |zipfile|
- playlist.tracks.each do |track|
- next unless track.audio.attached?
- audio_path = Rails.root.join("tmp", track.slug)
- track.audio.download do |chunk|
- File.open(audio_path, "ab") { |file| file.write(chunk) }
+ def playlist_zip(playlist)
+ zip_file = Tempfile.new(["#{playlist.slug}-#{playlist.id}", '.zip'])
+
+ begin
+ Zip::File.open(zip_file.path, Zip::File::CREATE) do |zipfile|
+ playlist.tracks.each do |track|
+ next unless track.audio.attached?
+
+ begin
+ track.audio.open do |file|
+ # Use the original filename from the blob
+ filename = track.audio.filename.to_s
+ # Add the file directly to the zip without creating a separate temp file
+ zipfile.get_output_stream(filename) do |os|
+ IO.copy_stream(file, os)
+ end
+ end
+ rescue StandardError => e
+ Rails.logger.error("Error processing track #{track.id}: #{e.message}")
+ end
end
-
- zipfile.add(track.audio.filename.to_s, audio_path)
- File.delete(audio_path) # Clean up the downloaded audio file
end
+
+ # Attach the zipped file to the playlist
+ playlist.zip.attach(
+ io: File.open(zip_file.path),
+ filename: "#{playlist.slug}.zip",
+ content_type: 'application/zip'
+ )
+
+ # # Broadcast the update (commented out as requested)
+ # Turbo::StreamsChannel.broadcast_replace_to(
+ # "playlist_#{playlist.id}",
+ # target: "playlist_#{playlist.id}_download",
+ # partial: 'playlists/download_ready',
+ # locals: { playlist: playlist }
+ # )
+
+ true # Return true if successful
+ rescue StandardError => e
+ Rails.logger.error("Failed to create zip for playlist #{playlist.id}: #{e.message}")
+
+ # # Broadcast error message (commented out as requested)
+ # Turbo::StreamsChannel.broadcast_replace_to(
+ # "playlist_#{playlist.id}",
+ # target: "playlist_#{playlist.id}_download",
+ # partial: 'playlists/download_error',
+ # locals: { playlist: playlist, error: e.message }
+ # )
+
+ false # Return false if failed
+ ensure
+ zip_file.close
+ zip_file.unlink
end
-
- # Here you can attach the zipped file to the playlist or whatever you want
- # e.g.
- playlist.zip.attach(
- io: File.open(zipfile_path),
- filename: "#{playlist.slug}.zip"
- )
- # or store it somewhere else or let the user download it directly.
-
- # Clean up the generated zip file if you're not attaching it
- File.delete(zipfile_path)
end
+
end
diff --git a/app/models/playlist.rb b/app/models/playlist.rb
index 0876eca..06d9f52 100644
--- a/app/models/playlist.rb
+++ b/app/models/playlist.rb
@@ -57,6 +57,10 @@ def check_label
store_accessor :metadata, :price, :decimal
store_accessor :metadata, :name_your_price, :boolean
+ def name_your_price?
+ name_your_price.present?
+ end
+
def cover_url(size = nil)
url = case size
when :medium
diff --git a/app/models/purchased_item.rb b/app/models/purchased_item.rb
index c07e517..fe56b4a 100644
--- a/app/models/purchased_item.rb
+++ b/app/models/purchased_item.rb
@@ -15,12 +15,27 @@ class PurchasedItem < ApplicationRecord
def qr
url = Rails.application.routes.url_helpers.event_event_ticket_url(purchase.purchasable, signed_id)
- encoded_url = ERB::Util.url_encode(url)
- size = 120
- data_param = "chl=#{encoded_url}"
- google_charts_url = "https://chart.googleapis.com/chart?cht=qr&chs=#{size}x#{size}{data_param}"
+ qrcode = RQRCode::QRCode.new(url)
+
+ # Generate PNG data
+ png = qrcode.as_png(
+ bit_depth: 1,
+ border_modules: 4,
+ color_mode: ChunkyPNG::COLOR_GRAYSCALE,
+ color: 'black',
+ file: nil,
+ fill: 'white',
+ module_px_size: 6,
+ resize_exactly_to: false,
+ resize_gte_to: false,
+ size: 250
+ )
+
+ # Convert to base64 for embedding in HTML
+ base64_image = Base64.strict_encode64(png.to_s)
+ "data:image/png;base64,#{base64_image}"
end
-
+
def toggle_check_in!
if checked_in?
update({checked_in: false, checked_in_at: nil})
diff --git a/app/models/track.rb b/app/models/track.rb
index d2a191e..ef47ee4 100644
--- a/app/models/track.rb
+++ b/app/models/track.rb
@@ -113,6 +113,10 @@ def peaks=(peaks)
end
end
+ def presicion_for_currency
+ 0
+ end
+
def cover_url(size = nil)
url = case size
when :medium
diff --git a/app/views/event_purchases/show.html.erb b/app/views/event_purchases/show.html.erb
index 333de14..2b178b3 100644
--- a/app/views/event_purchases/show.html.erb
+++ b/app/views/event_purchases/show.html.erb
@@ -1,28 +1,26 @@
-
+
-
-
Order placed
-
+
<%= l @purchase.created_at, format: :long %>
-
+
View invoice
→
@@ -33,7 +31,7 @@
Products purchased
-
+
<% @purchase.purchased_items.each do |item| %>
@@ -48,11 +46,13 @@
-
+
<%= link_to item.purchased_item.title, event_event_ticket_path(@event, item.signed_id) %>
- <%= number_to_currency item.purchased_item.price %>
-
+
+ <%= number_to_currency item.purchased_item.price %>
+
+
<%= item.purchased_item.short_description %>
@@ -62,19 +62,19 @@
-
Delivery address
-
+ Delivery address
+
Floyd Miles
7363 Cynthia Pass
Toronto, ON N3Y 4H8
-
Shipping updates
-
+ Shipping updates
+
f•••@example.com
1•••••••••40
- Edit
+ Edit
@@ -83,16 +83,16 @@
+
+ Products purchased
+
+
+
+
+ <% @purchase.purchased_items.each do |item| %>
+
+
+
+
+ <%= image_tag item.purchased_item.cover_url(:small), class: "h-full w-full object-cover object-center sm:h-full sm:w-full" %>
+
+
+
+
+ <%= link_to item.purchased_item.title, playlist_path(@playlist) %>
+
+
<%= number_to_currency item.purchased_item.price %>
+
+ <%= item.purchased_item.zip.url %> ooo
+ <% # link_to "Downloads", item.purchased_item.zip.url %>
+
+
+
+
+
+
+
+
+
+ <% end %>
+
+
+
+
+
+
+
+
+
+
diff --git a/app/views/playlists/_playlist_item.html.erb b/app/views/playlists/_playlist_item.html.erb
index 8783a12..4059880 100644
--- a/app/views/playlists/_playlist_item.html.erb
+++ b/app/views/playlists/_playlist_item.html.erb
@@ -158,7 +158,7 @@
- <%= gettext("Buy Digital Album") %>
+ <%= t("payments.buy_digital_album") %>
diff --git a/app/views/playlists/show.html.erb b/app/views/playlists/show.html.erb
index 35067eb..d443328 100644
--- a/app/views/playlists/show.html.erb
+++ b/app/views/playlists/show.html.erb
@@ -291,6 +291,12 @@
<%= auto_link sanitize(@playlist.description, auto_link: true) %>
+
+ <% if @playlist.price %>
+ <%= render "shared/music_purchase", resource: @playlist %>
+ <% end %>
+
+
diff --git a/app/views/purchases/_download_error.erb b/app/views/purchases/_download_error.erb
new file mode 100644
index 0000000..23aaad9
--- /dev/null
+++ b/app/views/purchases/_download_error.erb
@@ -0,0 +1,3 @@
+<%= turbo_frame_tag "purchase_#{purchase.id}_download" do %>
+ error
+<% end %>
\ No newline at end of file
diff --git a/app/views/purchases/_download_processing.erb b/app/views/purchases/_download_processing.erb
new file mode 100644
index 0000000..0b973a9
--- /dev/null
+++ b/app/views/purchases/_download_processing.erb
@@ -0,0 +1,4 @@
+<%= turbo_frame_tag "purchase_#{purchase.id}_download" do %>
+ Your download is being prepared...
+ <%= turbo_frame_tag "purchase_#{purchase.id}_download_status", src: check_zip_status_purchase_path(purchase), refresh: { interval: 5000 } %>
+<% end %>
\ No newline at end of file
diff --git a/app/views/purchases/_download_ready.erb b/app/views/purchases/_download_ready.erb
new file mode 100644
index 0000000..8d3c34e
--- /dev/null
+++ b/app/views/purchases/_download_ready.erb
@@ -0,0 +1,4 @@
+<%= turbo_frame_tag "purchase_#{purchase.id}_download" do %>
+ <%= link_to "Download ZIP", purchase.purchasable.zip.url(expires_in: 5.minute, disposition: "attachment"), class: "btn btn-primary" %>
+ (This links lasts 5 minutes)
+<% end %>
\ No newline at end of file
diff --git a/app/views/purchases/_track.erb b/app/views/purchases/_track.erb
index b15982a..6182d6d 100644
--- a/app/views/purchases/_track.erb
+++ b/app/views/purchases/_track.erb
@@ -1,8 +1,5 @@
- <%= purchase.id %>
- <%= purchase.state %>
-
<% purchase.purchased_items.each do |item|%>
@@ -12,21 +9,26 @@
) %>
- <%= link_to track_path(item.purchased_item.slug) do %>
+ <%= link_to item.purchased_item do %>
<%= item.purchased_item.title %>
- <%= gettext("Created at:") %> <%= purchase.created_at %>
+ <%= gettext("Created at:") %> <%= l purchase.created_at, format: :short %>
<% end %>
<% end %>
+ <% case purchase.state %>
+ <% when "paid" %>
+
Paid
+ <% when "pending" %>
+
Pending
+ <% end %>
+
<% if purchase.is_downloadable? %>
-
- <%= link_to purchase_url(purchase.signed_id), class: "group block", target: "_blank" do %>
- <%= gettext("Download link") %>
- <% end %>
-
+ <%= turbo_frame_tag "purchase_#{purchase.id}_download" do %>
+ <%= button_to "Prepare Download", download_purchase_path(purchase), method: :get, class: "truncate text-sm font-medium text-brand-600" %>
+ <% end %>
<% end %>
\ No newline at end of file
diff --git a/app/views/purchases/music.html.erb b/app/views/purchases/music.html.erb
index 93694c4..6225302 100644
--- a/app/views/purchases/music.html.erb
+++ b/app/views/purchases/music.html.erb
@@ -42,7 +42,7 @@
-
+
<%= t("purchases.my_music", section: @section) %>
@@ -51,7 +51,6 @@
<%= link_to music_purchases_path(tab: "albums"),
- phx_click: "section-change", phx_value_section: "all_music",
class: "border-transparent text-gray-500 dark:text-gray-200 hover:text-gray-700 hover:text-gray-300 hover:border-gray-200 whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm" do %>
<%= t("purchases.purchased_albums") %>
@@ -73,6 +72,11 @@
+
+
+
<% @collection.each do |purchase| %>
<%= render "track", purchase: purchase %>
diff --git a/app/views/purchases/tickets.html.erb b/app/views/purchases/tickets.html.erb
index 8bcb87d..d94bdcc 100644
--- a/app/views/purchases/tickets.html.erb
+++ b/app/views/purchases/tickets.html.erb
@@ -118,7 +118,7 @@
- purchased on: <%= "Cldr.DateTime.to_string!(ticket.inserted_at)" %>
+ purchased on: <%= l(purchase.created_at, format: :short) %>
<% if false #ticket.checked_in_at %>
diff --git a/app/views/shared/_music_purchase.html.erb b/app/views/shared/_music_purchase.html.erb
index d8c3dc5..790d6ed 100644
--- a/app/views/shared/_music_purchase.html.erb
+++ b/app/views/shared/_music_purchase.html.erb
@@ -1,16 +1,26 @@
- <%= link_to new_track_track_purchase_path(@track),
- "data-turbo-frame": "modal",
- class: "hover:underline dark:border-white border-black rounded-lg border-2 p-2 bg-green-500 hover:bg-green-500/90" do %>
- <%= t("tracks.buy_digital_music")%>
+ <% if resource.is_a?(Track) %>
+ <%= link_to new_track_track_purchase_path(resource),
+ "data-turbo-frame": "modal",
+ class: "hover:underline dark:border-white border-black rounded-lg border-2 p-2 bg-green-500 hover:bg-green-500/90" do %>
+ <%= t("tracks.buy_digital_music")%>
+ <% end %>
+ <% end %>
+ <% if resource.is_a?(Playlist) %>
+ <%= link_to new_playlist_playlist_purchase_path(resource),
+ "data-turbo-frame": "modal",
+ class: "hover:underline dark:border-white border-black rounded-lg border-2 p-2 bg-green-500 hover:bg-green-500/90" do %>
+ <%= t("tracks.buy_digital_music")%>
+ <% end %>
<% end %>
<%= number_to_currency(resource.price) %> USD
- <% if resource.name_your_price? %>
+ <% if resource.name_your_price.present? %>
(<%= t("tracks.or_more") %>)
<% end %>
+
diff --git a/app/views/track_purchases/_form.html.erb b/app/views/track_purchases/_form.html.erb
index 97a8be1..4559a59 100644
--- a/app/views/track_purchases/_form.html.erb
+++ b/app/views/track_purchases/_form.html.erb
@@ -37,6 +37,7 @@
+
<% if form.object.include_message %>
<%= form.text_area(:optional_message,
@@ -55,6 +56,7 @@
+
<% if @payment.valid? %>
diff --git a/app/views/track_purchases/show.html.erb b/app/views/track_purchases/show.html.erb
index 564eec3..1b96736 100644
--- a/app/views/track_purchases/show.html.erb
+++ b/app/views/track_purchases/show.html.erb
@@ -1,26 +1,26 @@
-
+
Order placed
-
+
<%= l @purchase.created_at, format: :long %>
-
+
View invoice
→
@@ -31,25 +31,24 @@
Products purchased
-
+
<% @purchase.purchased_items.each do |item| %>
- <%= image_tag item.purchased_item.cover_url(:small) , class: "h-full w-full object-cover object-center sm:h-full sm:w-full" %>
+ <%= image_tag item.purchased_item.cover_url(:small), class: "h-full w-full object-cover object-center sm:h-full sm:w-full" %>
-
- <%= link_to item.purchased_item.title, event_event_ticket_path(@track, item.signed_id) %>
+
+ <%= link_to item.purchased_item.title, track_path(@track) %>
- <%= number_to_currency item.purchased_item.price %>
-
- <%= item.purchased_item.id %>
+
<%= number_to_currency item.purchased_item.price %>
+
+ <%= item.purchased_item.zip.url %> ooo
<%= link_to "Downloads", item.purchased_item.zip.url %>
-
@@ -58,19 +57,19 @@
-
Delivery address
-
+ Delivery address
+
Floyd Miles
7363 Cynthia Pass
Toronto, ON N3Y 4H8
-
Shipping updates
-
+ Shipping updates
+
f•••@example.com
1•••••••••40
- Edit
+ Edit
@@ -79,16 +78,16 @@