From 72c9ca9635d646394ada5bdf9b5177fdb86ac170 Mon Sep 17 00:00:00 2001 From: Arnaud Delcasse Date: Tue, 1 Nov 2022 17:06:12 +0100 Subject: [PATCH] Files management for bookings --- handlers/application/vehicles-management.go | 6 +- handlers/application/vehicles.go | 83 ++++- main.go | 2 + renderer/vehicle-management.go | 13 +- renderer/vehicles.go | 42 ++- .../default/web/layouts/support/support.html | 4 +- .../web/layouts/vehicles/booking-display.html | 53 ++- .../default/web/layouts/vehicles/search.html | 82 ++++- .../vehicles_management/booking-display.html | 49 +++ themes/default/web/public/css/main.css | 322 ++++++++++-------- utils/storage/files.go | 2 + utils/storage/minio.go | 20 ++ 12 files changed, 509 insertions(+), 169 deletions(-) diff --git a/handlers/application/vehicles-management.go b/handlers/application/vehicles-management.go index 761b127..79dc247 100644 --- a/handlers/application/vehicles-management.go +++ b/handlers/application/vehicles-management.go @@ -10,6 +10,7 @@ import ( "git.coopgo.io/coopgo-apps/parcoursmob/utils/identification" "git.coopgo.io/coopgo-apps/parcoursmob/utils/sorting" + filestorage "git.coopgo.io/coopgo-apps/parcoursmob/utils/storage" fleets "git.coopgo.io/coopgo-platform/fleets/grpcapi" fleetsstorage "git.coopgo.io/coopgo-platform/fleets/storage" groupsmanagement "git.coopgo.io/coopgo-platform/groups-management/grpcapi" @@ -303,5 +304,8 @@ func (h ApplicationHandler) VehicleManagementBookingDisplay(w http.ResponseWrite return } - h.Renderer.VehicleManagementBookingDisplay(w, r, booking, booking.Vehicle, beneficiaryresp.Account.ToStorageType(), groupresp.Group.ToStorageType()) + documents := h.filestorage.List(filestorage.PREFIX_BOOKINGS + "/" + bookingid) + file_types_map := h.config.GetStringMapString("storage.files.file_types") + + h.Renderer.VehicleManagementBookingDisplay(w, r, booking, booking.Vehicle, beneficiaryresp.Account.ToStorageType(), groupresp.Group.ToStorageType(), documents, file_types_map) } diff --git a/handlers/application/vehicles.go b/handlers/application/vehicles.go index 5755614..5c4a501 100644 --- a/handlers/application/vehicles.go +++ b/handlers/application/vehicles.go @@ -3,16 +3,20 @@ package application import ( "context" "fmt" + "io" "net/http" "sort" + "strings" "time" "git.coopgo.io/coopgo-apps/parcoursmob/utils/identification" "git.coopgo.io/coopgo-apps/parcoursmob/utils/sorting" + filestorage "git.coopgo.io/coopgo-apps/parcoursmob/utils/storage" fleets "git.coopgo.io/coopgo-platform/fleets/grpcapi" groupsmanagement "git.coopgo.io/coopgo-platform/groups-management/grpcapi" "git.coopgo.io/coopgo-platform/groups-management/storage" mobilityaccounts "git.coopgo.io/coopgo-platform/mobility-accounts/grpcapi" + mobilityaccountsstorage "git.coopgo.io/coopgo-platform/mobility-accounts/storage" "github.com/coreos/go-oidc" "github.com/google/uuid" "github.com/gorilla/mux" @@ -23,7 +27,9 @@ import ( func (h ApplicationHandler) VehiclesSearch(w http.ResponseWriter, r *http.Request) { r.ParseForm() - var beneficiary any + var beneficiary mobilityaccountsstorage.Account + + beneficiarydocuments := []filestorage.FileInfo{} vehicles := []any{} searched := false @@ -65,6 +71,8 @@ func (h ApplicationHandler) VehiclesSearch(w http.ResponseWriter, r *http.Reques vehicles = append(vehicles, v) } } + + beneficiarydocuments = h.filestorage.List(filestorage.PREFIX_BENEFICIARIES + "/" + beneficiary.ID) } accounts, err := h.beneficiaries(r) @@ -76,7 +84,10 @@ func (h ApplicationHandler) VehiclesSearch(w http.ResponseWriter, r *http.Reques sort.Sort(sorting.BeneficiariesByName(accounts)) - h.Renderer.VehiclesSearch(w, r, accounts, searched, vehicles, beneficiary, r.FormValue("startdate"), r.FormValue("enddate")) + mandatory_documents := h.config.GetStringSlice("modules.fleets.booking_documents.mandatory") + file_types_map := h.config.GetStringMapString("storage.files.file_types") + + h.Renderer.VehiclesSearch(w, r, accounts, searched, vehicles, beneficiary, r.FormValue("startdate"), r.FormValue("enddate"), mandatory_documents, file_types_map, beneficiarydocuments) } func (h ApplicationHandler) Book(w http.ResponseWriter, r *http.Request) { @@ -111,7 +122,7 @@ func (h ApplicationHandler) Book(w http.ResponseWriter, r *http.Request) { vehicleid := vars["vehicleid"] beneficiaryid := vars["beneficiaryid"] - r.ParseForm() + r.ParseMultipartForm(10 * 1024 * 1024) start := r.FormValue("startdate") end := r.FormValue("enddate") @@ -153,6 +164,42 @@ func (h ApplicationHandler) Book(w http.ResponseWriter, r *http.Request) { Booking: booking, } + fmt.Println(r.FormFile("doc-identity_proof")) + for _, v := range h.config.GetStringSlice("modules.fleets.booking_documents.mandatory") { + existing_file := r.FormValue("type-" + v) + if existing_file == "" { + file, header, err := r.FormFile("doc-" + v) + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte("Document manquant : " + v)) + return + } + defer file.Close() + + fileid := uuid.NewString() + + metadata := map[string]string{ + "type": v, + "name": header.Filename, + } + + if err := h.filestorage.Put(file, filestorage.PREFIX_BOOKINGS, fmt.Sprintf("%s/%s_%s", booking.Id, fileid, header.Filename), header.Size, metadata); err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + } else { + path := strings.Split(existing_file, "/") + + if err := h.filestorage.Copy(existing_file, fmt.Sprintf("%s/%s/%s", filestorage.PREFIX_BOOKINGS, booking.Id, path[len(path)-1])); err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + } + } + _, err = h.services.GRPC.Fleets.CreateBooking(context.TODO(), request) if err != nil { fmt.Println(err) @@ -202,7 +249,10 @@ func (h ApplicationHandler) VehicleBookingDisplay(w http.ResponseWriter, r *http return } - h.Renderer.VehicleBookingDisplay(w, r, booking, booking.Vehicle, beneficiaryresp.Account.ToStorageType(), groupresp.Group.ToStorageType()) + documents := h.filestorage.List(filestorage.PREFIX_BOOKINGS + "/" + bookingid) + file_types_map := h.config.GetStringMapString("storage.files.file_types") + + h.Renderer.VehicleBookingDisplay(w, r, booking, booking.Vehicle, beneficiaryresp.Account.ToStorageType(), groupresp.Group.ToStorageType(), documents, file_types_map) } func (h ApplicationHandler) VehiclesBookingsList(w http.ResponseWriter, r *http.Request) { @@ -222,3 +272,28 @@ func (h ApplicationHandler) VehiclesBookingsList(w http.ResponseWriter, r *http. h.Renderer.VehicleBookingsList(w, r, bookings) } + +func (h *ApplicationHandler) BookingDocumentDownload(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + bookingid := vars["bookingid"] + document := vars["document"] + + fmt.Println(fmt.Sprintf("%s/%s", bookingid, document)) + + file, info, err := h.filestorage.Get(filestorage.PREFIX_BOOKINGS, fmt.Sprintf("%s/%s", bookingid, document)) + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", info.ContentType) + if _, err = io.Copy(w, file); err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + http.Redirect(w, r, fmt.Sprintf("/app/vehicles/bookings/%s", bookingid), http.StatusFound) + +} diff --git a/main.go b/main.go index d158e04..e01324d 100644 --- a/main.go +++ b/main.go @@ -89,12 +89,14 @@ func main() { application.HandleFunc("/vehicles/bookings/", applicationHandler.VehiclesBookingsList) application.HandleFunc("/vehicles/bookings/{bookingid}", applicationHandler.VehicleBookingDisplay) application.HandleFunc("/vehicles/v/{vehicleid}/b/{beneficiaryid}", applicationHandler.Book) + application.HandleFunc("/vehicles/bookings/{bookingid}/documents/{document}", applicationHandler.BookingDocumentDownload) application.HandleFunc("/vehicles-management/", applicationHandler.VehiclesManagementOverview) application.HandleFunc("/vehicles-management/fleet/add", applicationHandler.VehiclesFleetAdd) application.HandleFunc("/vehicles-management/fleet/{vehicleid}", applicationHandler.VehiclesFleetDisplay) application.HandleFunc("/vehicles-management/fleet/{vehicleid}/update", applicationHandler.VehiclesFleetUpdate) application.HandleFunc("/vehicles-management/bookings/", applicationHandler.VehiclesManagementBookingsList) application.HandleFunc("/vehicles-management/bookings/{bookingid}", applicationHandler.VehicleManagementBookingDisplay) + application.HandleFunc("/vehicles-management/bookings/{bookingid}/documents/{document}", applicationHandler.BookingDocumentDownload) application.HandleFunc("/agenda/", applicationHandler.AgendaHome) application.HandleFunc("/agenda/create-event", applicationHandler.AgendaCreateEvent) application.HandleFunc("/agenda/{eventid}", applicationHandler.AgendaDisplayEvent) diff --git a/renderer/vehicle-management.go b/renderer/vehicle-management.go index 7b7533f..3dbd057 100644 --- a/renderer/vehicle-management.go +++ b/renderer/vehicle-management.go @@ -3,6 +3,7 @@ package renderer import ( "net/http" + filestorage "git.coopgo.io/coopgo-apps/parcoursmob/utils/storage" fleetsstorage "git.coopgo.io/coopgo-platform/fleets/storage" ) @@ -59,14 +60,16 @@ func (renderer *Renderer) VehiclesFleetUpdate(w http.ResponseWriter, r *http.Req renderer.Render("fleet display vehicle", w, r, files, state) } -func (renderer *Renderer) VehicleManagementBookingDisplay(w http.ResponseWriter, r *http.Request, booking any, vehicle any, beneficiary any, group any) { +func (renderer *Renderer) VehicleManagementBookingDisplay(w http.ResponseWriter, r *http.Request, booking any, vehicle any, beneficiary any, group any, documents []filestorage.FileInfo, file_types_map map[string]string) { files := renderer.ThemeConfig.GetStringSlice("views.vehicles_management.booking_display.files") state := NewState(r, renderer.ThemeConfig, vehiclesmanagementMenu) state.ViewState = map[string]any{ - "booking": booking, - "vehicle": vehicle, - "beneficiary": beneficiary, - "group": group, + "booking": booking, + "vehicle": vehicle, + "beneficiary": beneficiary, + "group": group, + "documents": documents, + "file_types_map": file_types_map, } renderer.Render("vehicles search", w, r, files, state) diff --git a/renderer/vehicles.go b/renderer/vehicles.go index 4ec0184..945f04a 100644 --- a/renderer/vehicles.go +++ b/renderer/vehicles.go @@ -1,14 +1,28 @@ package renderer import ( + "fmt" "net/http" + filestorage "git.coopgo.io/coopgo-apps/parcoursmob/utils/storage" mobilityaccountsstorage "git.coopgo.io/coopgo-platform/mobility-accounts/storage" ) const vehiclesMenu = "vehicles" -func (renderer *Renderer) VehiclesSearch(w http.ResponseWriter, r *http.Request, beneficiaries []mobilityaccountsstorage.Account, searched bool, vehicles []any, beneficiary any, startdate any, enddate any) { +func selectDocumentsDefaults(beneficiarydocuments []filestorage.FileInfo, mandatory_documents []string) map[string]string { + res := map[string]string{} + for _, v := range mandatory_documents { + for _, d := range beneficiarydocuments { + if d.Metadata["Type"] == v { + res[v] = d.Key + } + } + } + return res +} + +func (renderer *Renderer) VehiclesSearch(w http.ResponseWriter, r *http.Request, beneficiaries []mobilityaccountsstorage.Account, searched bool, vehicles []any, beneficiary any, startdate any, enddate any, mandatory_documents []string, file_types_map map[string]string, beneficiarydocuments []filestorage.FileInfo) { files := renderer.ThemeConfig.GetStringSlice("views.vehicles.search.files") state := NewState(r, renderer.ThemeConfig, vehiclesMenu) viewstate := map[string]any{ @@ -16,12 +30,18 @@ func (renderer *Renderer) VehiclesSearch(w http.ResponseWriter, r *http.Request, "searched": searched, } + fmt.Println(mandatory_documents) + if searched { viewstate["search"] = map[string]any{ - "startdate": startdate, - "enddate": enddate, - "vehicles": vehicles, - "beneficiary": beneficiary, + "startdate": startdate, + "enddate": enddate, + "vehicles": vehicles, + "beneficiary": beneficiary, + "mandatory_documents": mandatory_documents, + "file_types_map": file_types_map, + "beneficiary_documents": beneficiarydocuments, + "documents_defaults": selectDocumentsDefaults(beneficiarydocuments, mandatory_documents), } } @@ -30,14 +50,16 @@ func (renderer *Renderer) VehiclesSearch(w http.ResponseWriter, r *http.Request, renderer.Render("vehicles search", w, r, files, state) } -func (renderer *Renderer) VehicleBookingDisplay(w http.ResponseWriter, r *http.Request, booking any, vehicle any, beneficiary any, group any) { +func (renderer *Renderer) VehicleBookingDisplay(w http.ResponseWriter, r *http.Request, booking any, vehicle any, beneficiary any, group any, documents []filestorage.FileInfo, file_types_map map[string]string) { files := renderer.ThemeConfig.GetStringSlice("views.vehicles.booking_display.files") state := NewState(r, renderer.ThemeConfig, vehiclesMenu) state.ViewState = map[string]any{ - "booking": booking, - "vehicle": vehicle, - "beneficiary": beneficiary, - "group": group, + "booking": booking, + "vehicle": vehicle, + "beneficiary": beneficiary, + "group": group, + "documents": documents, + "file_types_map": file_types_map, } renderer.Render("vehicles search", w, r, files, state) diff --git a/themes/default/web/layouts/support/support.html b/themes/default/web/layouts/support/support.html index d54ece2..224bd63 100644 --- a/themes/default/web/layouts/support/support.html +++ b/themes/default/web/layouts/support/support.html @@ -1,10 +1,10 @@ {{define "content"}}
-

Demande de support

+

Demande de support technique

- Le support PARCOURSMOB est ouvert les jours ouvrés de 9h à 18h. Vous pouvez également nous joindre par email à support@parcoursmob.fr, par exemple pour nous envoyez des copies d'écran du problème que vous rencontrez. + Le support technique PARCOURSMOB est ouvert les jours ouvrés de 9h à 18h. Vous pouvez également nous joindre par email à support@parcoursmob.fr, par exemple pour nous envoyez des copies d'écran du problème que vous rencontrez.

diff --git a/themes/default/web/layouts/vehicles/booking-display.html b/themes/default/web/layouts/vehicles/booking-display.html index 9a08d5a..21d19c3 100644 --- a/themes/default/web/layouts/vehicles/booking-display.html +++ b/themes/default/web/layouts/vehicles/booking-display.html @@ -76,10 +76,10 @@

Informations utiles sur la réservation.

- + class="relative inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-xs font-medium rounded-2xl text-co-blue bg-gray-100 hover:bg-co-blue hover:text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-co-blue">Email -->
@@ -141,6 +141,55 @@
{{(timeFrom .ViewState.booking.Enddate).Format "02/01/2006"}}
+
+

Documents

+ {{if eq (len .ViewState.documents) 0}} +

Aucun document

+ {{end}} + + + {{if gt (len .ViewState.documents) 0}} + +
+ + + + + + + + + + + {{range .ViewState.documents}} + + + + + + + {{end}} + + + + +
Type + Actions +
+
+ {{index $.ViewState.file_types_map .Metadata.Type}} +
+
+

{{.Metadata.Name}}

+
{{.LastModified.Format "02/01/2006"}} + + + +
+
+ + {{end}} +
diff --git a/themes/default/web/layouts/vehicles/search.html b/themes/default/web/layouts/vehicles/search.html index d0d87c6..b9d4845 100644 --- a/themes/default/web/layouts/vehicles/search.html +++ b/themes/default/web/layouts/vehicles/search.html @@ -141,8 +141,86 @@ {{.Data.licence_plate}} COOPGO {{if .Data.address}}{{.Data.address.properties.label}}{{end}} - - Réserver pour {{$.ViewState.search.beneficiary.Data.first_name}} {{$.ViewState.search.beneficiary.Data.last_name}} + + + Réserver pour {{$.ViewState.search.beneficiary.Data.first_name}} {{$.ViewState.search.beneficiary.Data.last_name}} + {{end}} diff --git a/themes/default/web/layouts/vehicles_management/booking-display.html b/themes/default/web/layouts/vehicles_management/booking-display.html index 995544e..2a767fd 100644 --- a/themes/default/web/layouts/vehicles_management/booking-display.html +++ b/themes/default/web/layouts/vehicles_management/booking-display.html @@ -216,6 +216,55 @@ +
+

Documents

+ {{if eq (len .ViewState.documents) 0}} +

Aucun document

+ {{end}} + + + {{if gt (len .ViewState.documents) 0}} + +
+ + + + + + + + + + + {{range .ViewState.documents}} + + + + + + + {{end}} + + + + +
Type + Actions +
+
+ {{index $.ViewState.file_types_map .Metadata.Type}} +
+
+

{{.Metadata.Name}}

+
{{.LastModified.Format "02/01/2006"}} + + + +
+
+ + {{end}} +
diff --git a/themes/default/web/public/css/main.css b/themes/default/web/public/css/main.css index cb99184..868f308 100644 --- a/themes/default/web/public/css/main.css +++ b/themes/default/web/public/css/main.css @@ -806,18 +806,6 @@ html { left: 1rem; } -.left-6 { - left: 1.5rem; -} - -.-top-px { - top: -1px; -} - -.right-6 { - right: 1.5rem; -} - .z-40 { z-index: 40; } @@ -850,6 +838,15 @@ html { margin: 0.5rem; } +.m-4 { + margin: 1rem; +} + +.-mx-4 { + margin-left: -1rem; + margin-right: -1rem; +} + .mx-auto { margin-left: auto; margin-right: auto; @@ -860,11 +857,6 @@ html { margin-bottom: -0.5rem; } -.-mx-4 { - margin-left: -1rem; - margin-right: -1rem; -} - .my-4 { margin-top: 1rem; margin-bottom: 1rem; @@ -913,6 +905,14 @@ html { margin-top: 0.25rem; } +.mt-10 { + margin-top: 2.5rem; +} + +.mr-2 { + margin-right: 0.5rem; +} + .mr-4 { margin-right: 1rem; } @@ -933,10 +933,6 @@ html { margin-top: 0.75rem; } -.mt-10 { - margin-top: 2.5rem; -} - .mr-3 { margin-right: 0.75rem; } @@ -961,10 +957,6 @@ html { margin-bottom: 1rem; } -.mr-2 { - margin-right: 0.5rem; -} - .ml-6 { margin-left: 1.5rem; } @@ -981,6 +973,10 @@ html { margin-top: -1rem; } +.mb-10 { + margin-bottom: 2.5rem; +} + .-mt-2 { margin-top: -0.5rem; } @@ -1005,10 +1001,6 @@ html { margin-right: -0.25rem; } -.mb-10 { - margin-bottom: 2.5rem; -} - .block { display: block; } @@ -1033,6 +1025,10 @@ html { display: table; } +.table-cell { + display: table-cell; +} + .flow-root { display: flow-root; } @@ -1085,10 +1081,6 @@ html { height: 0.75rem; } -.h-px { - height: 1px; -} - .max-h-60 { max-height: 15rem; } @@ -1157,14 +1149,18 @@ html { width: 0px; } -.min-w-0 { - min-width: 0px; +.w-20 { + width: 5rem; } .min-w-full { min-width: 100%; } +.min-w-0 { + min-width: 0px; +} + .max-w-xs { max-width: 20rem; } @@ -1185,6 +1181,14 @@ html { max-width: 32rem; } +.max-w-sm { + max-width: 24rem; +} + +.max-w-full { + max-width: 100%; +} + .flex-1 { flex: 1 1 0%; } @@ -1209,6 +1213,10 @@ html { flex-grow: 1; } +.table-fixed { + table-layout: fixed; +} + .origin-top-right { transform-origin: top right; } @@ -1228,6 +1236,16 @@ html { transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } +.translate-y-4 { + --tw-translate-y: 1rem; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + +.translate-y-0 { + --tw-translate-y: 0px; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + .scale-95 { --tw-scale-x: .95; --tw-scale-y: .95; @@ -1309,6 +1327,10 @@ html { align-items: flex-start; } +.items-end { + align-items: flex-end; +} + .items-center { align-items: center; } @@ -1428,16 +1450,16 @@ html { border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); } -.divide-gray-200 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-opacity: 1; - border-color: rgb(229 231 235 / var(--tw-divide-opacity)); -} - .divide-gray-300 > :not([hidden]) ~ :not([hidden]) { --tw-divide-opacity: 1; border-color: rgb(209 213 219 / var(--tw-divide-opacity)); } +.divide-gray-200 > :not([hidden]) ~ :not([hidden]) { + --tw-divide-opacity: 1; + border-color: rgb(229 231 235 / var(--tw-divide-opacity)); +} + .overflow-auto { overflow: auto; } @@ -1531,11 +1553,6 @@ html { border-bottom-left-radius: 1rem; } -.rounded-t-lg { - border-top-left-radius: 0.5rem; - border-top-right-radius: 0.5rem; -} - .border { border-width: 1px; } @@ -1674,6 +1691,10 @@ html { --tw-bg-opacity: 0.75; } +.bg-opacity-30 { + --tw-bg-opacity: 0.3; +} + .stroke-gray-800 { stroke: #1f2937; } @@ -1682,14 +1703,14 @@ html { stroke: #fff; } -.p-12 { - padding: 3rem; -} - .p-1 { padding: 0.25rem; } +.p-12 { + padding: 3rem; +} + .p-2 { padding: 0.5rem; } @@ -1698,18 +1719,14 @@ html { padding: 1rem; } -.p-1\.5 { - padding: 0.375rem; -} - -.p-8 { - padding: 2rem; -} - .p-0 { padding: 0px; } +.p-1\.5 { + padding: 0.375rem; +} + .px-4 { padding-left: 1rem; padding-right: 1rem; @@ -1730,6 +1747,26 @@ html { padding-bottom: 1.5rem; } +.py-3\.5 { + padding-top: 0.875rem; + padding-bottom: 0.875rem; +} + +.py-3 { + padding-top: 0.75rem; + padding-bottom: 0.75rem; +} + +.px-3 { + padding-left: 0.75rem; + padding-right: 0.75rem; +} + +.py-4 { + padding-top: 1rem; + padding-bottom: 1rem; +} + .px-2 { padding-left: 0.5rem; padding-right: 0.5rem; @@ -1745,31 +1782,11 @@ html { padding-bottom: 2.5rem; } -.py-4 { - padding-top: 1rem; - padding-bottom: 1rem; -} - .px-1 { padding-left: 0.25rem; padding-right: 0.25rem; } -.px-3 { - padding-left: 0.75rem; - padding-right: 0.75rem; -} - -.py-3\.5 { - padding-top: 0.875rem; - padding-bottom: 0.875rem; -} - -.py-3 { - padding-top: 0.75rem; - padding-bottom: 0.75rem; -} - .py-12 { padding-top: 3rem; padding-bottom: 3rem; @@ -1813,20 +1830,20 @@ html { padding-right: 2.25rem; } -.pr-2 { - padding-right: 0.5rem; -} - -.pr-12 { - padding-right: 3rem; +.pl-4 { + padding-left: 1rem; } .pr-4 { padding-right: 1rem; } -.pl-4 { - padding-left: 1rem; +.pr-2 { + padding-right: 0.5rem; +} + +.pr-12 { + padding-right: 3rem; } .pl-1 { @@ -1837,10 +1854,18 @@ html { padding-right: 2.5rem; } +.pb-2 { + padding-bottom: 0.5rem; +} + .pt-8 { padding-top: 2rem; } +.pb-6 { + padding-bottom: 1.5rem; +} + .pt-4 { padding-top: 1rem; } @@ -1865,14 +1890,6 @@ html { padding-left: 0.375rem; } -.pb-6 { - padding-bottom: 1.5rem; -} - -.pb-2 { - padding-bottom: 0.5rem; -} - .text-left { text-align: left; } @@ -1899,6 +1916,11 @@ html { line-height: 1.5rem; } +.text-xs { + font-size: 0.75rem; + line-height: 1rem; +} + .text-2xl { font-size: 1.5rem; line-height: 2rem; @@ -1909,11 +1931,6 @@ html { line-height: 1.75rem; } -.text-xs { - font-size: 0.75rem; - line-height: 1rem; -} - .text-xl { font-size: 1.25rem; line-height: 1.75rem; @@ -1952,14 +1969,14 @@ html { text-transform: capitalize; } -.leading-6 { - line-height: 1.5rem; -} - .leading-4 { line-height: 1rem; } +.leading-6 { + line-height: 1.5rem; +} + .leading-5 { line-height: 1.25rem; } @@ -2017,16 +2034,16 @@ html { color: rgb(22 101 52 / var(--tw-text-opacity)); } -.text-co-green { - --tw-text-opacity: 1; - color: rgb(108 193 31 / var(--tw-text-opacity)); -} - .text-gray-600 { --tw-text-opacity: 1; color: rgb(75 85 99 / var(--tw-text-opacity)); } +.text-co-green { + --tw-text-opacity: 1; + color: rgb(108 193 31 / var(--tw-text-opacity)); +} + .text-black { --tw-text-opacity: 1; color: rgb(0 0 0 / var(--tw-text-opacity)); @@ -2094,6 +2111,12 @@ html { box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } +.shadow-xl { + --tw-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + .ring-1 { --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); @@ -2123,16 +2146,16 @@ html { --tw-ring-color: rgb(0 0 0 / var(--tw-ring-opacity)); } -.ring-white { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(255 255 255 / var(--tw-ring-opacity)); -} - .ring-gray-300 { --tw-ring-opacity: 1; --tw-ring-color: rgb(209 213 219 / var(--tw-ring-opacity)); } +.ring-white { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(255 255 255 / var(--tw-ring-opacity)); +} + .ring-opacity-5 { --tw-ring-opacity: 0.05; } @@ -2168,6 +2191,12 @@ html { transition-duration: 150ms; } +.transition-all { + transition-property: all; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; +} + .duration-300 { transition-duration: 300ms; } @@ -2235,11 +2264,6 @@ html { --tw-ring-color: rgb(36 56 135 / var(--tw-ring-opacity)); } -.focus-within\:ring-indigo-500:focus-within { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity)); -} - .focus-within\:ring-offset-2:focus-within { --tw-ring-offset-width: 2px; } @@ -2317,11 +2341,6 @@ html { color: inherit; } -.hover\:text-indigo-500:hover { - --tw-text-opacity: 1; - color: rgb(99 102 241 / var(--tw-text-opacity)); -} - .focus\:border-transparent:focus { border-color: transparent; } @@ -2341,11 +2360,6 @@ html { border-color: rgb(59 130 246 / var(--tw-border-opacity)); } -.focus\:border-indigo-600:focus { - --tw-border-opacity: 1; - border-color: rgb(79 70 229 / var(--tw-border-opacity)); -} - .focus\:placeholder-gray-400:focus::-moz-placeholder { --tw-placeholder-opacity: 1; color: rgb(156 163 175 / var(--tw-placeholder-opacity)); @@ -2482,6 +2496,11 @@ html { margin-right: auto; } + .sm\:my-8 { + margin-top: 2rem; + margin-bottom: 2rem; + } + .sm\:mt-0 { margin-top: 0px; } @@ -2494,12 +2513,16 @@ html { margin-left: 1.25rem; } - .sm\:block { - display: block; + .sm\:mt-5 { + margin-top: 1.25rem; } - .sm\:inline { - display: inline; + .sm\:mt-6 { + margin-top: 1.5rem; + } + + .sm\:block { + display: block; } .sm\:flex { @@ -2530,6 +2553,10 @@ html { max-width: 28rem; } + .sm\:max-w-sm { + max-width: 24rem; + } + .sm\:flex-auto { flex: 1 1 auto; } @@ -2542,6 +2569,23 @@ html { flex: 1 1 0%; } + .sm\:translate-y-0 { + --tw-translate-y: 0px; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + } + + .sm\:scale-95 { + --tw-scale-x: .95; + --tw-scale-y: .95; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + } + + .sm\:scale-100 { + --tw-scale-x: 1; + --tw-scale-y: 1; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + } + .sm\:grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } @@ -2625,6 +2669,10 @@ html { padding: 1.5rem; } + .sm\:p-0 { + padding: 0px; + } + .sm\:px-6 { padding-left: 1.5rem; padding-right: 1.5rem; @@ -2676,14 +2724,6 @@ html { grid-column: span 2 / span 2; } - .md\:col-span-3 { - grid-column: span 3 / span 3; - } - - .md\:col-span-6 { - grid-column: span 6 / span 6; - } - .md\:mx-0 { margin-left: 0px; margin-right: 0px; @@ -2826,10 +2866,6 @@ html { display: table-cell; } - .lg\:hidden { - display: none; - } - .lg\:max-w-7xl { max-width: 80rem; } diff --git a/utils/storage/files.go b/utils/storage/files.go index 056bafb..aad384d 100644 --- a/utils/storage/files.go +++ b/utils/storage/files.go @@ -9,6 +9,7 @@ import ( const ( PREFIX_BENEFICIARIES = "beneficiaries" + PREFIX_BOOKINGS = "fleets_bookings" ) type FileInfo struct { @@ -23,6 +24,7 @@ type FileStorage interface { Put(reader io.Reader, prefix string, filename string, size int64, metadata map[string]string) error List(prefix string) []FileInfo Get(prefix string, file string) (io.Reader, *FileInfo, error) + Copy(src string, dest string) error } func NewFileStorage(cfg *viper.Viper) (FileStorage, error) { diff --git a/utils/storage/minio.go b/utils/storage/minio.go index 5cfbe03..bd7ea57 100644 --- a/utils/storage/minio.go +++ b/utils/storage/minio.go @@ -102,3 +102,23 @@ func (s *MinioStorageHandler) Get(prefix string, file string) (io.Reader, *FileI return object, fileinfo, nil } + +func (s *MinioStorageHandler) Copy(src string, dst string) error { + srcOpts := minio.CopySrcOptions{ + Bucket: s.BucketName, + Object: src, + } + + // Destination object + dstOpts := minio.CopyDestOptions{ + Bucket: s.BucketName, + Object: dst, + } + + _, err := s.Client.CopyObject(context.Background(), dstOpts, srcOpts) + if err != nil { + fmt.Println(err) + return err + } + return nil +}