Files management for bookings
This commit is contained in:
parent
cb36a7c8dd
commit
72c9ca9635
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
||||
}
|
||||
|
|
2
main.go
2
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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
{{define "content"}}
|
||||
|
||||
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 space-y-6">
|
||||
<h1 class="text-2xl font-semibold text-gray-900">Demande de support</h1>
|
||||
<h1 class="text-2xl font-semibold text-gray-900">Demande de support technique</h1>
|
||||
<div class="bg-white py-2 px-4 shadow sm:rounded-lg sm:px-10">
|
||||
<p class="text-sm text-gray-600 p-4">
|
||||
Le support PARCOURSMOB est ouvert les jours ouvrés de 9h à 18h. Vous pouvez également nous joindre par email à <b class="text-co-blue"><a href="mailto:support@parcoursmob.fr">support@parcoursmob.fr</a></b>, 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 à <b class="text-co-blue"><a href="mailto:support@parcoursmob.fr">support@parcoursmob.fr</a></b>, par exemple pour nous envoyez des copies d'écran du problème que vous rencontrez.
|
||||
</p>
|
||||
<form action="" method="POST">
|
||||
|
||||
|
|
|
@ -76,10 +76,10 @@
|
|||
<p class="mt-1 text-sm text-gray-500">Informations utiles sur la réservation.</p>
|
||||
</div>
|
||||
<div class="ml-4 mt-4 flex-shrink-0">
|
||||
<button type="button"
|
||||
<!-- <button type="button"
|
||||
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">SMS</button>
|
||||
<button type="button"
|
||||
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</button>
|
||||
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</button> -->
|
||||
<!-- <button type="button"
|
||||
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">Imprimer</button> -->
|
||||
</div>
|
||||
|
@ -141,6 +141,55 @@
|
|||
<dd class="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">{{(timeFrom .ViewState.booking.Enddate).Format
|
||||
"02/01/2006"}}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm font-medium text-gray-500 my-4">Documents</p>
|
||||
{{if eq (len .ViewState.documents) 0}}
|
||||
<p class="p-12 text-gray-500 text-center text-md">Aucun document</p>
|
||||
{{end}}
|
||||
|
||||
|
||||
{{if gt (len .ViewState.documents) 0}}
|
||||
|
||||
<div class="-mx-4 mb-10 ring-1 ring-gray-300 sm:-mx-6 md:mx-0 md:rounded-lg">
|
||||
<table class="min-w-full divide-y divide-gray-300 table-fixed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6">Type</th>
|
||||
<th scope="col" class="hidden px-3 py-3.5 text-left text-sm font-semibold text-gray-900 lg:table-cell">Nom du document</th>
|
||||
<th scope="col" class="hidden px-3 py-3.5 text-left text-sm font-semibold text-gray-900 lg:table-cell">Ajouté le</th>
|
||||
<th scope="col" class="relative py-3.5 pl-3 pr-4 sm:pr-6">
|
||||
<span class="sr-only">Actions</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .ViewState.documents}}
|
||||
<tr>
|
||||
<td class="relative py-4 pl-4 sm:pl-6 pr-3 text-sm">
|
||||
<div class="font-medium text-gray-900">
|
||||
<span class="bg-co-blue text-xs text-white rounded-xl p-1 mr-2">{{index $.ViewState.file_types_map .Metadata.Type}}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-3 py-3.5 text-sm text-gray-900 table-cell max-w-10 overflow-hidden">
|
||||
<p class=" overflow-hidden">{{.Metadata.Name}}</p>
|
||||
</td>
|
||||
<td class="px-3 py-3.5 text-sm text-gray-500 lg:table-cell">{{.LastModified.Format "02/01/2006"}}</td>
|
||||
<td class="relative py-3.5 pl-3 pr-4 sm:pr-6 text-right text-sm font-medium">
|
||||
<a href="/app/vehicles/bookings/{{$.ViewState.booking.ID}}/documents/{{.FileName}}" target="_blank">
|
||||
<button type="button" class="inline-flex items-center rounded-md border border-gray-300 bg-white px-3 py-2 text-sm font-medium leading-4 text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-co-blue focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-30">Voir<span class="sr-only"> le document</span></button>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
|
||||
|
||||
<!-- More plans... -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{{end}}
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -141,8 +141,86 @@
|
|||
<td class="whitespace-nowrap py-4 px-3 text-sm text-gray-500">{{.Data.licence_plate}}</td>
|
||||
<td class="whitespace-nowrap py-4 px-3 text-sm text-gray-500">COOPGO</td>
|
||||
<td class="whitespace-nowrap py-4 px-3 text-sm text-gray-500">{{if .Data.address}}{{.Data.address.properties.label}}{{end}}</td>
|
||||
<td class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6 md:pr-0">
|
||||
<a href="/app/vehicles/v/{{.ID}}/b/{{$.ViewState.search.beneficiary.ID}}?startdate={{$.ViewState.search.startdate}}&enddate={{$.ViewState.search.enddate}}" class="text-co-blue hover:text-co-blue">Réserver<span class="sr-only"> pour {{$.ViewState.search.beneficiary.Data.first_name}} {{$.ViewState.search.beneficiary.Data.last_name}}</span></a>
|
||||
<td class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6 md:pr-0"
|
||||
x-data="{
|
||||
documentsdialog: false
|
||||
}">
|
||||
<!-- <a href="/app/vehicles/v/{{.ID}}/b/{{$.ViewState.search.beneficiary.ID}}?startdate={{$.ViewState.search.startdate}}&enddate={{$.ViewState.search.enddate}}" class="text-co-blue hover:text-co-blue">Réserver<span class="sr-only"> pour {{$.ViewState.search.beneficiary.Data.first_name}} {{$.ViewState.search.beneficiary.Data.last_name}}</span></a> -->
|
||||
<a href="#" @click="documentsdialog = !documentsdialog" class="text-co-blue hover:text-co-blue">Réserver<span class="sr-only"> pour {{$.ViewState.search.beneficiary.Data.first_name}} {{$.ViewState.search.beneficiary.Data.last_name}}</span></a>
|
||||
<div class="relative z-10" aria-labelledby="modal-title" role="dialog" aria-modal="true"
|
||||
x-show="documentsdialog">
|
||||
<!--
|
||||
Background backdrop, show/hide based on modal state.
|
||||
|
||||
Entering: "ease-out duration-300"
|
||||
From: "opacity-0"
|
||||
To: "opacity-100"
|
||||
Leaving: "ease-in duration-200"
|
||||
From: "opacity-100"
|
||||
To: "opacity-0"
|
||||
-->
|
||||
<div class="fixed inset-0 bg-gray-900 bg-opacity-30 transition-opacity"></div>
|
||||
|
||||
<div class="fixed inset-0 z-10 overflow-y-auto">
|
||||
<div class="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
|
||||
<!--
|
||||
Modal panel, show/hide based on modal state.
|
||||
|
||||
Entering: "ease-out duration-300"
|
||||
From: "opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
To: "opacity-100 translate-y-0 sm:scale-100"
|
||||
Leaving: "ease-in duration-200"
|
||||
From: "opacity-100 translate-y-0 sm:scale-100"
|
||||
To: "opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
-->
|
||||
<div class="relative transform overflow-hidden rounded-lg bg-white px-4 pt-5 pb-4 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-sm sm:p-6">
|
||||
<div>
|
||||
<div class="mx-auto flex h-12 w-12 items-center justify-center rounded-co bg-co-blue">
|
||||
<!-- Heroicon name: outline/check -->
|
||||
{{$.IconSet.Icon "hero:outline/folder-plus" "h-6 w-6 text-white"}}
|
||||
<!-- <svg class="h-6 w-6 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5" />
|
||||
</svg> -->
|
||||
</div>
|
||||
<div class="mt-3 text-center sm:mt-5">
|
||||
<h3 class="text-lg font-medium leading-6 text-gray-900" id="modal-title">Documents demandés</h3>
|
||||
<div class="mt-2">
|
||||
<p class="text-sm text-gray-500">Ajoutez des documents pour finaliser</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form enctype="multipart/form-data" method="POST" action="/app/vehicles/v/{{.ID}}/b/{{$.ViewState.search.beneficiary.ID}}?startdate={{$.ViewState.search.startdate}}&enddate={{$.ViewState.search.enddate}}">
|
||||
{{range $.ViewState.search.mandatory_documents}}
|
||||
{{$type := .}}
|
||||
<div class="p-2"
|
||||
x-data="{
|
||||
select: '{{index $.ViewState.search.documents_defaults $type}}'
|
||||
}">
|
||||
<label for="type" class="block text-sm font-medium text-gray-700">{{index $.ViewState.search.file_types_map $type}}</label>
|
||||
<select x-model="select" id="type-{{$type}}" name="type-{{$type}}" class="mt-1 block w-full rounded-2xl border-gray-300 py-2 pl-3 pr-10 text-base focus:border-co-blue focus:outline-none focus:ring-co-blue sm:text-sm">
|
||||
{{range $.ViewState.search.beneficiary_documents}}
|
||||
{{if eq $type .Metadata.Type}}
|
||||
<option value="{{.Key}}">Fichier bénéficiaire : {{.Metadata.Name}}</option>
|
||||
{{end}}
|
||||
{{end}}
|
||||
<option value="">Ajouter un fichier</option>
|
||||
</select>
|
||||
<div x-show="select == ''" class="p-2">
|
||||
<input type="file" name="doc-{{$type}}" />
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="mt-5 sm:mt-6">
|
||||
<button type="submit" class="inline-flex w-full justify-center rounded-2xl border border-transparent bg-co-blue px-4 py-2 text-base font-medium text-white shadow-sm hover:bg-co-blue focus:outline-none focus:ring-2 focus:ring-co-blue focus:ring-offset-2 sm:text-sm">Réserver</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="mt-5 sm:mt-6">
|
||||
<button @click="documentsdialog=false" type="button" class="inline-flex w-full justify-center max-w-xs bg-white hover:bg-gray-50 border-gray-300 border px-4 py-2 text-gray-700 items-center text-sm rounded-2xl focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-co-blue">Annuler</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
|
|
|
@ -216,6 +216,55 @@
|
|||
</button>
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm font-medium text-gray-500 my-4">Documents</p>
|
||||
{{if eq (len .ViewState.documents) 0}}
|
||||
<p class="p-12 text-gray-500 text-center text-md">Aucun document</p>
|
||||
{{end}}
|
||||
|
||||
|
||||
{{if gt (len .ViewState.documents) 0}}
|
||||
|
||||
<div class="-mx-4 mb-10 ring-1 ring-gray-300 sm:-mx-6 md:mx-0 md:rounded-lg">
|
||||
<table class="min-w-full divide-y divide-gray-300 table-fixed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6">Type</th>
|
||||
<th scope="col" class="hidden px-3 py-3.5 text-left text-sm font-semibold text-gray-900 lg:table-cell">Nom du document</th>
|
||||
<th scope="col" class="hidden px-3 py-3.5 text-left text-sm font-semibold text-gray-900 lg:table-cell">Ajouté le</th>
|
||||
<th scope="col" class="relative py-3.5 pl-3 pr-4 sm:pr-6">
|
||||
<span class="sr-only">Actions</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .ViewState.documents}}
|
||||
<tr>
|
||||
<td class="relative py-4 pl-4 sm:pl-6 pr-3 text-sm">
|
||||
<div class="font-medium text-gray-900">
|
||||
<span class="bg-co-blue text-xs text-white rounded-xl p-1 mr-2">{{index $.ViewState.file_types_map .Metadata.Type}}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-3 py-3.5 text-sm text-gray-900 table-cell max-w-10 overflow-hidden">
|
||||
<p class=" overflow-hidden">{{.Metadata.Name}}</p>
|
||||
</td>
|
||||
<td class="px-3 py-3.5 text-sm text-gray-500 lg:table-cell">{{.LastModified.Format "02/01/2006"}}</td>
|
||||
<td class="relative py-3.5 pl-3 pr-4 sm:pr-6 text-right text-sm font-medium">
|
||||
<a href="/app/vehicles/bookings/{{$.ViewState.booking.ID}}/documents/{{.FileName}}" target="_blank">
|
||||
<button type="button" class="inline-flex items-center rounded-md border border-gray-300 bg-white px-3 py-2 text-sm font-medium leading-4 text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-co-blue focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-30">Voir<span class="sr-only"> le document</span></button>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
|
||||
|
||||
<!-- More plans... -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{{end}}
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue