Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

react UI #270

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.23.2
go-version: 1.23.4

- name: go vet
run: go vet ./...
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.23.2
go-version: 1.23.4

- name: Build binaries
run: make build_all
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -258,3 +258,13 @@ In case you'd like to add some other features to the logbook or you found a bug,
* Signature Pad https://github.com/szimek/signature_pad
* PapaParse https://github.com/mholt/PapaParse
* arc.js https://github.com/springmeyer/arc.js


* Golang go-pdf https://github.com/go-pdf/fpdf
* Golang chi web-server https://github.com/go-chi/chi
* React https://react.dev/
* Material UI https://mui.com/material-ui/
* Material React Table https://material-react-table.com
* dayjs https://github.com/iamkun/dayjs
* TanStack Query https://tanstack.com/query/
* export-to-csv https://github.com/alexcaza/export-to-csv
12 changes: 11 additions & 1 deletion app/handlers_aircraft.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"github.com/vsimakhin/web-logbook/internal/models"
)

// HandlerNightTime is a handler for calculating night time
func (app *application) HandlerAircrafts(w http.ResponseWriter, r *http.Request) {

var aircrafts map[string]string
Expand All @@ -27,3 +26,14 @@ func (app *application) HandlerAircrafts(w http.ResponseWriter, r *http.Request)

app.writeJSON(w, http.StatusOK, aircrafts)
}

// HandlerApiAircraftModels is a handler for getting the list of aircraft models/types
func (app *application) HandlerApiAircraftModels(w http.ResponseWriter, r *http.Request) {

models, err := app.db.GetAircraftModels()
if err != nil {
app.handleError(w, err)
}

app.writeJSON(w, http.StatusOK, models)
}
11 changes: 8 additions & 3 deletions app/handlers_airport.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,28 @@ import (

// HandlerAirportByID returns airport record by ID (ICAO or IATA)
func (app *application) HandlerAirportByID(w http.ResponseWriter, r *http.Request) {
uuid := chi.URLParam(r, "id")
uuid := strings.ToUpper(chi.URLParam(r, "id"))

airport, err := app.db.GetAirportByID(uuid)
if err != nil {
app.errorLog.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
app.handleError(w, err)
return
}

if airport.IATA == "" && airport.ICAO == "" {
// looks like there is no such ID in airport database
app.warningLog.Printf("cannot find %s in the airport database\n", uuid)
app.writeJSON(w, http.StatusNotFound, models.JSONResponse{OK: false, Message: "Airport not found"})
return
}

app.writeJSON(w, http.StatusOK, airport)
}

/////////////////////////////////////////////////
// for futher review
/////////////////////////////////////////////////

func (app *application) downloadAirportDB(source string) ([]models.Airport, error) {
var airports []models.Airport
var airportsDB map[string]interface{}
Expand Down
21 changes: 21 additions & 0 deletions app/handlers_aux.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"fmt"
"io/fs"
"net/http"
"strings"
)

//go:embed static
Expand Down Expand Up @@ -73,3 +74,23 @@

app.writeJSON(w, http.StatusOK, data)
}

//go:embed ui/dist/*

Check failure on line 78 in app/handlers_aux.go

View workflow job for this annotation

GitHub Actions / build

pattern ui/dist/*: no matching files found
var ui embed.FS

func (app *application) HandlerUI() http.Handler {
// Subdirectory inside the embedded FS where the React build is located
dist, _ := fs.Sub(ui, "ui/dist")

fileServer := http.FileServer(http.FS(dist))

return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
requestedPath := r.URL.Path

if requestedPath != "/" && !strings.Contains(requestedPath, "assets") {
r.URL.Path = "/"
}

fileServer.ServeHTTP(w, r)
})
}
14 changes: 0 additions & 14 deletions app/handlers_export.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,13 @@ import (
"net/http"

"github.com/go-chi/chi/v5"
"github.com/vsimakhin/web-logbook/internal/csvexport"
"github.com/vsimakhin/web-logbook/internal/models"
"github.com/vsimakhin/web-logbook/internal/pdfexport"
"github.com/vsimakhin/web-logbook/internal/xlsexport"
)

const exportA4 = "A4"
const exportA5 = "A5"
const exportCSV = "csv"
const exportXLS = "xls"

// HandlerExportPDFA4Page is a handler for /export-pdf-a4 page
Expand Down Expand Up @@ -103,15 +101,6 @@ func (app *application) HandlerExportLogbook(w http.ResponseWriter, r *http.Requ
return pdfExporter.ExportA5(flightRecords, w)
}

case exportCSV:
contentType = "text/csv"
fileName = "logbook.csv"
var e csvexport.ExportCSV
e.ExportCSV = settings.ExportCSV
exportFunc = func() error {
return e.Export(flightRecords, w)
}

case exportXLS:
contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
fileName = "logbook.xlsx"
Expand Down Expand Up @@ -160,9 +149,6 @@ func (app *application) HandlerExportSettingsSave(w http.ResponseWriter, r *http
} else if format == exportA5 {
currsettings.ExportA5 = settings.ExportA5

} else if format == exportCSV {
currsettings.ExportCSV = settings.ExportCSV

} else if format == exportXLS {
currsettings.ExportXLS = settings.ExportXLS

Expand Down
169 changes: 53 additions & 116 deletions app/handlers_flightrecord.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,177 +5,114 @@ import (
"fmt"
"math"
"net/http"
"time"

"github.com/go-chi/chi/v5"
"github.com/google/uuid"
"github.com/vsimakhin/web-logbook/internal/models"
)

// HandlerFlightRecordByID shows flight record by UUID
func (app *application) HandlerFlightRecordByID(w http.ResponseWriter, r *http.Request) {
func (app *application) HandlerApiFlightRecordByID(w http.ResponseWriter, r *http.Request) {
uuid := chi.URLParam(r, "uuid")

flightRecord, err := app.db.GetFlightRecordByID(uuid)
if err != nil {
app.errorLog.Println(fmt.Errorf("cannot find the flight record %s - %s", uuid, err))
http.Error(w, err.Error(), http.StatusInternalServerError)
app.handleError(w, err)
return
}

aircraftRegs, aircraftModels := app.lastRegsAndModels()

data := make(map[string]interface{})
data["flightRecord"] = flightRecord
data["aircraftRegs"] = aircraftRegs
data["aircraftModels"] = aircraftModels
data["enableHelpMessages"] = app.isFlightRecordHelpEnabled()

if err := app.renderTemplate(w, r, "flight-record", &templateData{Data: data}); err != nil {
app.errorLog.Println(err)
}
app.writeJSON(w, http.StatusOK, flightRecord)
}

// HandlerFlightRecordNew shows the empty form for a new flight record
func (app *application) HandlerFlightRecordNew(w http.ResponseWriter, r *http.Request) {
// HandlerNightTime is a handler for calculating night time
func (app *application) HandlerNightTime(w http.ResponseWriter, r *http.Request) {

var flightRecord models.FlightRecord
var fr models.FlightRecord
var response models.JSONResponse

// check if the page opened from the existing flight record
// in this case we can assume it's a next flight and we can set departure = last arrival
// and the date of the new record = same date
r.ParseForm()
lastArrival := r.FormValue("last_arrival")
if lastArrival != "" {
flightRecord.Departure.Place = lastArrival
err := json.NewDecoder(r.Body).Decode(&fr)
if err != nil {
app.errorLog.Println(fmt.Errorf("error calculating night time - %s", err))
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

lastDate := r.FormValue("last_date")
if lastDate != "" {
flightRecord.Date = lastDate
} else {
flightRecord.Date = time.Now().Format("02/01/2006")
night, err := app.calculateNightTime(fr)
if err != nil {
app.errorLog.Println(err)
return
}

aircraftRegs, aircraftModels := app.lastRegsAndModels()

data := make(map[string]interface{})
data["flightRecord"] = flightRecord
data["aircraftRegs"] = aircraftRegs
data["aircraftModels"] = aircraftModels
data["enableHelpMessages"] = app.isFlightRecordHelpEnabled()
response.OK = true
response.Data = fmt.Sprintf("%d", int(math.Round(night.Minutes())))

if err := app.renderTemplate(w, r, "flight-record", &templateData{Data: data}); err != nil {
app.errorLog.Println(err)
}
app.writeJSON(w, http.StatusOK, response)
}

// HandlerFlightRecordDelete serves POST request for deleting flight record
func (app *application) HandlerFlightRecordDelete(w http.ResponseWriter, r *http.Request) {

var flightRecord models.FlightRecord
var response models.JSONResponse
// HandlerApiFlightRecordDelete deletes the flight record
func (app *application) HandlerApiFlightRecordDelete(w http.ResponseWriter, r *http.Request) {
uuid := chi.URLParam(r, "uuid")

err := json.NewDecoder(r.Body).Decode(&flightRecord)
err := app.db.DeleteFlightRecord(uuid)
if err != nil {
app.errorLog.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
app.handleError(w, err)
return
}

err = app.db.DeleteFlightRecord(flightRecord.UUID)
if err != nil {
app.errorLog.Println(fmt.Errorf("error deleting the flight record - %s", err))
response.OK = false
response.Message = err.Error()
} else {
response.OK = true
response.Message = "Flight Record deleted"
response.RedirectURL = APILogbook

}

err = app.db.DeleteAttachmentsForFlightRecord(flightRecord.UUID)
err = app.db.DeleteAttachmentsForFlightRecord(uuid)
if err != nil {
app.errorLog.Println(err)
}

app.writeJSON(w, http.StatusOK, response)
app.writeOkResponse(w, "Flight record has been deleted")
}

// HandlerFlightRecordSave updates the flight record or create a new one
func (app *application) HandlerFlightRecordSave(w http.ResponseWriter, r *http.Request) {
// HandlerApiFlightRecordNew creates a new flight record
func (app *application) HandlerApiFlightRecordNew(w http.ResponseWriter, r *http.Request) {

var flightRecord models.FlightRecord
var response models.JSONResponse

err := json.NewDecoder(r.Body).Decode(&flightRecord)
if err != nil {
app.errorLog.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
app.handleError(w, err)
return
}

if flightRecord.UUID == "" {
// new flight record
uuid, err := uuid.NewRandom()
if err != nil {
app.errorLog.Println(err)
response.OK = false
response.Message = err.Error()
}

flightRecord.UUID = uuid.String()

err = app.db.InsertFlightRecord(flightRecord)
if err != nil {
app.errorLog.Println(fmt.Errorf("error creating a new flight record - %s", err))
response.OK = false
response.Message = err.Error()
} else {
response.OK = true
response.Message = "New Flight Record has been saved"
response.Data = flightRecord.UUID
}

} else {
// just update the current flight record
err = app.db.UpdateFlightRecord(flightRecord)
if err != nil {
app.errorLog.Println(fmt.Errorf("error updating the flight record - %s", err))
response.OK = false
response.Message = err.Error()
} else {
response.OK = true
response.Message = "Flight Record has been updated"

}
uuid, err := uuid.NewRandom()
if err != nil {
app.handleError(w, err)
return
}
flightRecord.UUID = uuid.String()

err = app.db.InsertFlightRecord(flightRecord)
if err != nil {
app.handleError(w, err)
return
}

var response models.JSONResponse
response.OK = true
response.Message = "New Flight Record created"
response.Data = flightRecord.UUID

app.writeJSON(w, http.StatusOK, response)
}

// HandlerNightTime is a handler for calculating night time
func (app *application) HandlerNightTime(w http.ResponseWriter, r *http.Request) {

var fr models.FlightRecord
var response models.JSONResponse
// HandlerApiFlightRecordUpdate updates the flight record
func (app *application) HandlerApiFlightRecordUpdate(w http.ResponseWriter, r *http.Request) {

err := json.NewDecoder(r.Body).Decode(&fr)
var flightRecord models.FlightRecord
err := json.NewDecoder(r.Body).Decode(&flightRecord)
if err != nil {
app.errorLog.Println(fmt.Errorf("error calculating night time - %s", err))
http.Error(w, err.Error(), http.StatusInternalServerError)
app.handleError(w, err)
return
}

night, err := app.calculateNightTime(fr)
err = app.db.UpdateFlightRecord(flightRecord)
if err != nil {
app.errorLog.Println(err)
app.handleError(w, err)
return
}

response.OK = true
response.Data = fmt.Sprintf("%d", int(math.Round(night.Minutes())))

app.writeJSON(w, http.StatusOK, response)
app.writeOkResponse(w, "Flight Record has been updated")
}
Loading
Loading