1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-08-09 23:45:21 +02:00
This commit is contained in:
neo773 2025-04-13 21:54:24 +05:30
parent 9733794096
commit e1296de458
No known key found for this signature in database
GPG key ID: 6B43F29FCC69B333
5 changed files with 107 additions and 22 deletions

View file

@ -6,6 +6,13 @@ class Import::UploadsController < ApplicationController
def show
end
def sample_csv
send_data @import.csv_template.to_csv,
filename: "#{@import.type.underscore.split('_').first}_sample.csv",
type: "text/csv",
disposition: "attachment"
end
def update
if csv_valid?(csv_str)
@import.account = Current.family.accounts.find_by(id: params.dig(:import, :account_id))

View file

@ -0,0 +1,74 @@
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ["input", "fileName", "uploadArea", "uploadText"]
connect() {
if (this.hasInputTarget) {
this.inputTarget.addEventListener("change", this.fileSelected.bind(this))
}
// Find the form element
this.form = this.element.closest("form")
if (this.form) {
this.form.addEventListener("turbo:submit-start", this.formSubmitting.bind(this))
}
}
disconnect() {
if (this.hasInputTarget) {
this.inputTarget.removeEventListener("change", this.fileSelected.bind(this))
}
if (this.form) {
this.form.removeEventListener("turbo:submit-start", this.formSubmitting.bind(this))
}
}
triggerFileInput() {
if (this.hasInputTarget) {
this.inputTarget.click()
}
}
fileSelected() {
if (this.hasInputTarget && this.inputTarget.files.length > 0) {
const fileName = this.inputTarget.files[0].name
if (this.hasFileNameTarget) {
// Find the paragraph element inside the fileName target
const fileNameText = this.fileNameTarget.querySelector('p')
if (fileNameText) {
fileNameText.textContent = fileName
}
this.fileNameTarget.classList.remove("hidden")
}
if (this.hasUploadTextTarget) {
this.uploadTextTarget.classList.add("hidden")
}
}
}
formSubmitting() {
if (this.hasFileNameTarget && this.hasInputTarget && this.inputTarget.files.length > 0) {
const fileNameText = this.fileNameTarget.querySelector('p')
if (fileNameText) {
fileNameText.textContent = `Uploading ${this.inputTarget.files[0].name}...`
}
// Change the icon to a loader
const iconContainer = this.fileNameTarget.querySelector('.lucide-file-text')
if (iconContainer) {
iconContainer.classList.add('animate-pulse')
}
}
if (this.hasUploadAreaTarget) {
this.uploadAreaTarget.classList.add("opacity-70")
}
}
}

View file

@ -4,7 +4,7 @@
<%= content_for :previous_path, imports_path %>
<div class="space-y-12">
<div class="space-y-4">
<div class="space-y-4 mx-auto max-w-md">
<div class="text-center space-y-2">
<h1 class="text-3xl text-primary font-medium"><%= t(".title") %></h1>
@ -39,11 +39,23 @@
placeholder: "Paste your CSV file contents here",
"data-auto-submit-form-target": "auto" %>
<% else %>
<label for="import_csv_file" class="flex flex-col items-center justify-center w-full h-56 border-2 border-secondary border-dashed rounded-lg cursor-pointer bg-container-inset">
<div class="flex flex-col items-center justify-center w-full h-64 border border-secondary border-dashed rounded-xl cursor-pointer" data-controller="file-upload" data-action="click->file-upload#triggerFileInput" data-file-upload-target="uploadArea">
<div class="flex flex-col items-center justify-center pt-5 pb-6">
<%= form.file_field :csv_file, class: "ml-32", "data-auto-submit-form-target": "auto" %>
<div data-file-upload-target="uploadText" class="flex flex-col items-center">
<%= lucide_icon("plus", class: "w-6 h-6 mb-4 text-secondary mx-auto") %>
<p class="mb-2 text-md text-gray text-center">
<span class="font-medium text-primary">Browse</span> to add your CSV file here
</p>
</div>
<div class="flex flex-col items-center hidden" data-file-upload-target="fileName">
<%= lucide_icon("file-text", class: "w-6 h-6 mb-4 text-primary") %>
<p class="mb-2 text-md font-medium text-primary"></p>
</div>
<%= form.file_field :csv_file, class: "hidden", "data-auto-submit-form-target": "auto", "data-file-upload-target": "input" %>
</div>
</label>
</div>
<% end %>
<%= form.submit "Upload CSV", disabled: @import.complete? %>
@ -53,22 +65,12 @@
</div>
</div>
<div class="bg-alpha-black-25 rounded-xl p-1 mt-5 mx-auto max-w-7xl">
<div class="text-secondary p-2 mb-2">
<div class="flex gap-2 mb-2">
<%= lucide_icon("info", class: "w-5 h-5 shrink-0") %>
<p class="text-sm"><%= t(".instructions_1") %></p>
<div class="flex justify-center">
<span class="text-secondary text-sm">
<%= link_to "Download a sample CSV", "/imports/#{@import.id}/upload/sample_csv", class: "text-primary underline", data: { turbo: false } %> to see the required CSV format
</span>
</div>
</div>
<ul class="list-disc list-inside text-sm pl-8">
<li><%= t(".instructions_2") %></li>
<li><%= t(".instructions_3") %></li>
<li><%= t(".instructions_4") %></li>
<li><%= t(".instructions_5") %></li>
</ul>
</div>
<%= render partial: "imports/table", locals: { headers: @import.csv_template.headers, rows: @import.csv_template } %>
</div>
</div>

View file

@ -1,5 +1,5 @@
<%= render "layouts/shared/htmldoc" do %>
<div class="flex flex-col h-dvh bg-surface pt-safe">
<div class="flex flex-col h-dvh bg-white pt-safe">
<header class="flex items-center justify-between p-8">
<%= link_to content_for(:previous_path) || imports_path do %>
<%= lucide_icon "arrow-left", class: "w-5 h-5 text-secondary" %>

View file

@ -203,6 +203,8 @@ Rails.application.routes.draw do
get "service-worker" => "rails/pwa#service_worker", as: :pwa_service_worker
get "manifest" => "rails/pwa#manifest", as: :pwa_manifest
get "imports/:import_id/upload/sample_csv", to: "import/uploads#sample_csv", as: :import_upload_sample_csv
# Defines the root path route ("/")
root "pages#dashboard"
end