diff --git a/apps/cli/main.go b/apps/cli/main.go deleted file mode 100644 index 839a9bc..0000000 --- a/apps/cli/main.go +++ /dev/null @@ -1,95 +0,0 @@ -package main - -import ( - "fmt" - "marmic/servicetrade-toolbox/internal/api" - "marmic/servicetrade-toolbox/internal/handlers/cli" - "marmic/servicetrade-toolbox/internal/ui" - "marmic/servicetrade-toolbox/internal/utils" - "os" -) - -func main() { - ui.DisplayStartScreen() - - email, password, err := utils.PromptCredentials() - if err != nil { - ui.DisplayError("Error getting credentials:", err) - os.Exit(1) - } - - session := api.NewSession() - err = session.Login(email, password) - if err != nil { - ui.DisplayError("Authentication failed:", err) - os.Exit(1) - } - - fmt.Println("Login successful!") - - for { - ui.ClearScreen() - fmt.Println("Main Menu:") - fmt.Println("1. Jobs") - fmt.Println("2. Invoices") - fmt.Println("3. Companies") - fmt.Println("4. Assets") - fmt.Println("5. Contacts") - fmt.Println("6. Contracts") - fmt.Println("7. Generic Tools") - fmt.Println("8. Locations") - fmt.Println("9. Notifications") - fmt.Println("10. Quotes") - fmt.Println("11. Services") - fmt.Println("12. Tags") - fmt.Println("13. Users") - fmt.Println("14. Admin") - fmt.Println("15. Logout") - - choice, err := utils.GetUserChoice(15) - if err != nil { - ui.DisplayError("Invalid input:", err) - utils.PressEnterToContinue() - continue - } - switch choice { - case 1: - cli.HandleJobs(session) - case 2: - cli.HandleInvoices(session) - case 3: - cli.HandleCompanies(session) - case 4: - cli.HandleAssets(session) - case 5: - cli.HandleContacts(session) - case 6: - cli.HandleContracts(session) - case 7: - cli.HandleGenericTools(session) - case 8: - cli.HandleLocations(session) - case 9: - cli.HandleNotifications(session) - case 10: - cli.HandleQuotes(session) - case 11: - cli.HandleServices(session) - case 12: - cli.HandleTags(session) - case 13: - cli.HandleUsers(session) - case 14: - cli.HandleAdmin(session) - case 15: - err := session.Logout() - if err != nil { - ui.DisplayError("Error during logout: ", err) - } else { - fmt.Println("Logout successful.") - } - fmt.Println("Exiting ServiceTrade CLI Toolbox. Goodbye!") - return - } - } -} diff --git a/apps/web/main.go b/apps/web/main.go index e4c89cf..8b5dd4f 100644 --- a/apps/web/main.go +++ b/apps/web/main.go @@ -58,6 +58,13 @@ func main() { protected.HandleFunc("/tags", web.TagsHandler).Methods("GET") protected.HandleFunc("/users", web.UsersHandler).Methods("GET") + // Document upload routes + protected.HandleFunc("/documents", web.DocumentsHandler).Methods("GET") + protected.HandleFunc("/process-csv", web.ProcessCSVHandler).Methods("POST") + protected.HandleFunc("/upload-documents", web.UploadDocumentsHandler).Methods("POST") + protected.HandleFunc("/document-field-add", web.DocumentFieldAddHandler).Methods("GET") + protected.HandleFunc("/document-field-remove", web.DocumentFieldRemoveHandler).Methods("GET") + log.Println("Server starting on :8080") log.Fatal(http.ListenAndServe(":8080", r)) } diff --git a/go.mod b/go.mod index 468e217..df7e9a9 100644 --- a/go.mod +++ b/go.mod @@ -2,13 +2,4 @@ module marmic/servicetrade-toolbox go 1.22.1 -require ( - github.com/gorilla/mux v1.8.1 - github.com/inancgumus/screen v0.0.0-20190314163918-06e984b86ed3 -) - -require ( - golang.org/x/crypto v0.28.0 // indirect - golang.org/x/sys v0.26.0 // indirect - golang.org/x/term v0.25.0 // indirect -) +require github.com/gorilla/mux v1.8.1 diff --git a/go.sum b/go.sum index e7a6e59..7128337 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,2 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -github.com/inancgumus/screen v0.0.0-20190314163918-06e984b86ed3 h1:fO9A67/izFYFYky7l1pDP5Dr0BTCRkaQJUG6Jm5ehsk= -github.com/inancgumus/screen v0.0.0-20190314163918-06e984b86ed3/go.mod h1:Ey4uAp+LvIl+s5jRbOHLcZpUDnkjLBROl15fZLwPlTM= -golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= -golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= -golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= diff --git a/internal/api/auth.go b/internal/api/auth.go index e4f92cc..9a51397 100644 --- a/internal/api/auth.go +++ b/internal/api/auth.go @@ -2,12 +2,11 @@ package api import ( "io" - "marmic/servicetrade-toolbox/internal/auth" "net/http" ) // AuthenticatedRequest wraps an http.Request with the session cookie -func AuthenticatedRequest(session *auth.Session, method, url string, body io.Reader) (*http.Request, error) { +func AuthenticatedRequest(session *Session, method, url string, body io.Reader) (*http.Request, error) { req, err := http.NewRequest(method, url, body) if err != nil { return nil, err @@ -17,6 +16,6 @@ func AuthenticatedRequest(session *auth.Session, method, url string, body io.Rea } // DoAuthenticatedRequest performs an authenticated request and returns the response -func DoAuthenticatedRequest(session *auth.Session, req *http.Request) (*http.Response, error) { +func DoAuthenticatedRequest(session *Session, req *http.Request) (*http.Response, error) { return session.Client.Do(req) } diff --git a/internal/api/deficiencies.go b/internal/api/deficiencies.go index f9839b7..9aa7cba 100644 --- a/internal/api/deficiencies.go +++ b/internal/api/deficiencies.go @@ -5,10 +5,9 @@ import ( "encoding/json" "fmt" "io" - "marmic/servicetrade-toolbox/internal/auth" ) -func GetDeficiencyById(session *auth.Session, deficiencyId string) (map[string]interface{}, error) { +func GetDeficiencyById(session *Session, deficiencyId string) (map[string]interface{}, error) { url := fmt.Sprintf("%s/deficiency/%s", BaseURL, deficiencyId) req, err := AuthenticatedRequest(session, "GET", url, nil) if err != nil { diff --git a/internal/api/jobs.go b/internal/api/jobs.go index c0cc6dd..2c9627d 100644 --- a/internal/api/jobs.go +++ b/internal/api/jobs.go @@ -5,153 +5,120 @@ import ( "fmt" "io" "log" + "net/http" "net/url" + "strconv" + "time" ) -type JobsResponse struct { - Data struct { - Jobs []Job `json:"jobs"` - } `json:"data"` +// SearchJobsParams defines parameters for searching jobs +type SearchJobsParams struct { + Query string + Status string + StartDate time.Time + EndDate time.Time + Page int + Limit int + IncludeArchived bool } -type Job struct { - ID int64 `json:"id"` - Name string `json:"name"` - CustomName *string `json:"customName"` - Type string `json:"type"` - JobTypeWeight int `json:"jobTypeWeight"` - Status string `json:"status"` - Visibility []string `json:"visibility"` - Number int `json:"number"` - RefNumber string `json:"refNumber"` - Description *string `json:"description"` - ScheduledDate *int64 `json:"scheduledDate"` - CompletedOn *int64 `json:"completedOn"` - ServiceLine string `json:"serviceLine"` - EstimatedPrice *float64 `json:"estimatedPrice"` - Vendor Vendor `json:"vendor"` - Customer Customer `json:"customer"` - Location Location `json:"location"` - Owner Owner `json:"owner"` - Tags []Tag `json:"tags"` - Appointments []Appointment `json:"appointments"` - CurrentAppointment Appointment `json:"currentAppointment"` - AssignedOffice Location `json:"assignedOffice"` - Offices []Location `json:"offices"` - Terms *Term `json:"terms"` - Contract *Contract `json:"contract"` - PrimaryContact *PrimaryContact `json:"primaryContact"` -} +// SearchJobs searches for jobs based on the provided parameters +func (s *Session) SearchJobs(params SearchJobsParams) ([]map[string]interface{}, error) { + queryValues := url.Values{} -type Vendor struct { - ID int64 `json:"id"` - URI string `json:"uri"` - Name string `json:"name"` - Status string `json:"status"` -} + if params.Query != "" { + queryValues.Add("q", params.Query) + } -type Customer struct { - ID int64 `json:"id"` - URI string `json:"uri"` - Name string `json:"name"` - Status string `json:"status"` -} + if params.Status != "" { + queryValues.Add("status", params.Status) + } -type Location struct { - ID int64 `json:"id"` - URI string `json:"uri"` - Name string `json:"name"` - RefNumber string `json:"refNumber"` - Lat float64 `json:"lat"` - Lon float64 `json:"lon"` - Address Address `json:"address"` -} + if !params.StartDate.IsZero() { + queryValues.Add("start", params.StartDate.Format("2006-01-02")) + } -type Address struct { - Street string `json:"street"` - City string `json:"city"` - State string `json:"state"` - PostalCode string `json:"postalCode"` -} + if !params.EndDate.IsZero() { + queryValues.Add("end", params.EndDate.Format("2006-01-02")) + } -func (a Address) String() string { - return fmt.Sprintf("%s, %s, %s %s", a.Street, a.City, a.State, a.PostalCode) -} + if params.Page > 0 { + queryValues.Add("page", strconv.Itoa(params.Page)) + } else { + queryValues.Add("page", "1") + } -type Owner struct { - ID int64 `json:"id"` - URI string `json:"uri"` - Name string `json:"name"` - Status string `json:"status"` - Email string `json:"email"` -} + if params.Limit > 0 { + queryValues.Add("limit", strconv.Itoa(params.Limit)) + } else { + queryValues.Add("limit", "50") + } -type Tag struct { - ID int64 `json:"id"` - URI string `json:"uri"` - Name string `json:"name"` -} + if params.IncludeArchived { + queryValues.Add("include", "archived") + } -type Appointment struct { - ID int64 `json:"id"` - URI string `json:"uri"` - Name string `json:"name"` - Status string `json:"status"` - WindowStart *int64 `json:"windowStart"` - WindowEnd *int64 `json:"windowEnd"` - Techs []Tech `json:"techs"` - Released bool `json:"released"` -} + endpoint := fmt.Sprintf("/job?%s", queryValues.Encode()) + resp, err := s.DoRequest(http.MethodGet, endpoint, nil) + if err != nil { + return nil, err + } + defer resp.Body.Close() -type Tech struct { - ID int64 `json:"id"` - Name string `json:"name"` - Email string `json:"email"` -} + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("error reading response body: %v", err) + } -type Term struct { - ID int64 `json:"id"` - Name string `json:"name"` -} + if resp.StatusCode != 200 { + return nil, fmt.Errorf("API returned error: %s - %s", resp.Status, string(body)) + } -type Contract struct { - ID int64 `json:"id"` - Name string `json:"name"` -} + var result struct { + Data struct { + Jobs []map[string]interface{} `json:"records"` + } `json:"data"` + } -type PrimaryContact struct { - ID int64 `json:"id"` - URI string `json:"uri"` - Email string `json:"email"` -} + if err := json.Unmarshal(body, &result); err != nil { + return nil, fmt.Errorf("error unmarshalling response: %v", err) + } -func (s *Session) SearchJobs(filters url.Values) ([]Job, error) { - endpoint := "/job?" - query := filters.Encode() - url := endpoint + query + log.Printf("Found %d jobs", len(result.Data.Jobs)) + log.Printf("Parsed Data: %+v", result.Data) + return result.Data.Jobs, nil +} - resp, err := s.DoRequest("GET", url, nil) +// GetJobDetails retrieves detailed information about a specific job +func (s *Session) GetJobDetails(jobID string) (map[string]interface{}, error) { + endpoint := fmt.Sprintf("/job/%s", jobID) + resp, err := s.DoRequest(http.MethodGet, endpoint, nil) if err != nil { return nil, err } defer resp.Body.Close() - body, _ := io.ReadAll(resp.Body) - log.Printf("Raw API Response: %s", string(body)) + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("error reading response body: %v", err) + } if resp.StatusCode != 200 { - return nil, fmt.Errorf("failed to search jobs: %s, response: %s", resp.Status, string(body)) + return nil, fmt.Errorf("API returned error: %s - %s", resp.Status, string(body)) + } + + var result struct { + Data map[string]interface{} `json:"data"` } - var result JobsResponse if err := json.Unmarshal(body, &result); err != nil { return nil, fmt.Errorf("error unmarshalling response: %v", err) } - log.Printf("Parsed Data: %+v", result.Data) - return result.Data.Jobs, nil + return result.Data, nil } +// GetAttachmentsForJob retrieves attachments for a specific job func (s *Session) GetAttachmentsForJob(jobID string) (map[string]interface{}, error) { resp, err := s.DoRequest("GET", fmt.Sprintf("/job/%s/paperwork", jobID), nil) if err != nil { @@ -171,21 +138,7 @@ func (s *Session) GetAttachmentsForJob(jobID string) (map[string]interface{}, er return result, nil } -func (s *Session) DeleteAttachment(attachmentID string) error { - resp, err := s.DoRequest("DELETE", fmt.Sprintf("/attachment/%s", attachmentID), nil) - if err != nil { - return err - } - defer resp.Body.Close() - - if resp.StatusCode != 200 && resp.StatusCode != 204 { - body, _ := io.ReadAll(resp.Body) - return fmt.Errorf("failed to delete attachment: %s, response: %s", resp.Status, string(body)) - } - - return nil -} - +// GetDeficiencyInfoForJob retrieves deficiency information for a specific job func (s *Session) GetDeficiencyInfoForJob(jobID string) ([]map[string]interface{}, error) { resp, err := s.DoRequest("GET", fmt.Sprintf("/deficiency/%s", jobID), nil) if err != nil { diff --git a/internal/auth/auth.go b/internal/auth/auth.go deleted file mode 100644 index 082586d..0000000 --- a/internal/auth/auth.go +++ /dev/null @@ -1,82 +0,0 @@ -package auth - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "net/http" - "strings" -) - -type Session struct { - Client *http.Client - Cookie string -} - -func NewSession() *Session { - return &Session{Client: &http.Client{}} -} - -func (s *Session) Login(email, password string) error { - url := "https://api.servicetrade.com/api/auth" - payload := map[string]string{ - "username": email, - "password": password, - } - payloadBytes, _ := json.Marshal(payload) - - req, err := http.NewRequest("POST", url, bytes.NewBuffer(payloadBytes)) - if err != nil { - return fmt.Errorf("error creating request: %v", err) - } - req.Header.Set("Content-Type", "application/json") - - resp, err := s.Client.Do(req) - if err != nil { - return fmt.Errorf("error sending request: %v", err) - } - defer resp.Body.Close() - - body, _ := io.ReadAll(resp.Body) - - if resp.StatusCode != 200 { - return fmt.Errorf("failed to authenticate: %s, response: %s", resp.Status, string(body)) - } - - for _, cookie := range resp.Cookies() { - if strings.Contains(cookie.Name, "PHPSESSID") { - s.Cookie = cookie.String() - return nil - } - } - - return fmt.Errorf("failed to retrieve session cookie; authentication may have failed") -} - -func (s *Session) Logout() error { - if s.Cookie == "" { - return fmt.Errorf("no active session to end") - } - - url := "https://api.servicetrade.com/api/auth" - req, err := http.NewRequest("DELETE", url, nil) - if err != nil { - return fmt.Errorf("failed to create DELETE request to end session: %v", err) - } - req.Header.Set("Cookie", s.Cookie) - - resp, err := s.Client.Do(req) - if err != nil { - return fmt.Errorf("failed to send DELETE request to end session: %v", err) - } - defer resp.Body.Close() - - if resp.StatusCode != 200 && resp.StatusCode != 204 { - body, _ := io.ReadAll(resp.Body) - return fmt.Errorf("failed to end session: %s, response: %s", resp.Status, string(body)) - } - - s.Cookie = "" - return nil -} diff --git a/internal/handlers/cli/admin.go b/internal/handlers/cli/admin.go deleted file mode 100644 index 379e598..0000000 --- a/internal/handlers/cli/admin.go +++ /dev/null @@ -1,48 +0,0 @@ -package cli - -import ( - "marmic/servicetrade-toolbox/internal/api" - "marmic/servicetrade-toolbox/internal/ui" - "marmic/servicetrade-toolbox/internal/utils" -) - -func HandleAdmin(session *api.Session) { - for { - ui.ClearScreen() - ui.DisplayMenu([]string{ - "User Management", - "System Settings", - "Back to Main Menu", - }, "Admin Menu") - - choice, err := utils.GetUserChoice(3) - if err != nil { - ui.DisplayError("Invalid input:", err) - utils.PressEnterToContinue() - continue - } - - switch choice { - case 1: - userManagement(session) - case 2: - systemSettings(session) - case 3: - return - } - } -} - -func userManagement(session *api.Session) { - ui.ClearScreen() - ui.DisplayMessage("User Management") - // TODO: Implement user management logic - utils.PressEnterToContinue() -} - -func systemSettings(session *api.Session) { - ui.ClearScreen() - ui.DisplayMessage("System Settings") - // TODO: Implement system settings logic - utils.PressEnterToContinue() -} diff --git a/internal/handlers/cli/assets.go b/internal/handlers/cli/assets.go deleted file mode 100644 index 3ee5ce0..0000000 --- a/internal/handlers/cli/assets.go +++ /dev/null @@ -1,67 +0,0 @@ -package cli - -import ( - "fmt" - "marmic/servicetrade-toolbox/internal/api" - "marmic/servicetrade-toolbox/internal/ui" - "marmic/servicetrade-toolbox/internal/utils" -) - -func HandleAssets(session *api.Session) { - for { - ui.ClearScreen() - fmt.Println("Assets Menu:") - fmt.Println("1. List Assets") - fmt.Println("2. Add Asset") - fmt.Println("3. Edit Asset") - fmt.Println("4. Delete Asset") - fmt.Println("5. Back to Main Menu") - - choice, err := utils.GetUserChoice(5) - if err != nil { - ui.DisplayError("Invalid input:", err) - utils.PressEnterToContinue() - continue - } - switch choice { - case 1: - listAssets(session) - case 2: - addAsset(session) - case 3: - editAsset(session) - case 4: - deleteAsset(session) - case 5: - return - } - } -} - -func listAssets(session *api.Session) { - ui.ClearScreen() - fmt.Println("Listing assets...") - // TODO: Implement asset listing logic using the API - utils.PressEnterToContinue() -} - -func addAsset(session *api.Session) { - ui.ClearScreen() - fmt.Println("Adding a new asset...") - // TODO: Implement asset creation logic using the API - utils.PressEnterToContinue() -} - -func editAsset(session *api.Session) { - ui.ClearScreen() - fmt.Println("Editing an asset...") - // TODO: Implement asset editing logic using the API - utils.PressEnterToContinue() -} - -func deleteAsset(session *api.Session) { - ui.ClearScreen() - fmt.Println("Deleting an asset...") - // TODO: Implement asset deletion logic using the API - utils.PressEnterToContinue() -} diff --git a/internal/handlers/cli/companies.go b/internal/handlers/cli/companies.go deleted file mode 100644 index c37e441..0000000 --- a/internal/handlers/cli/companies.go +++ /dev/null @@ -1,67 +0,0 @@ -package cli - -import ( - "fmt" - "marmic/servicetrade-toolbox/internal/api" - "marmic/servicetrade-toolbox/internal/ui" - "marmic/servicetrade-toolbox/internal/utils" -) - -func HandleCompanies(session *api.Session) { - for { - ui.ClearScreen() - fmt.Println("Companies Menu:") - fmt.Println("1. List Companies") - fmt.Println("2. Add Company") - fmt.Println("3. Edit Company") - fmt.Println("4. Delete Company") - fmt.Println("5. Back to Main Menu") - - choice, err := utils.GetUserChoice(5) - if err != nil { - ui.DisplayError("Invalid input:", err) - utils.PressEnterToContinue() - continue - } - switch choice { - case 1: - listCompanies(session) - case 2: - addCompany(session) - case 3: - editCompany(session) - case 4: - deleteCompany(session) - case 5: - return - } - } -} - -func listCompanies(session *api.Session) { - ui.ClearScreen() - fmt.Println("Listing companies...") - // TODO: Implement company listing logic using the API - utils.PressEnterToContinue() -} - -func addCompany(session *api.Session) { - ui.ClearScreen() - fmt.Println("Adding a new company...") - // TODO: Implement company creation logic using the API - utils.PressEnterToContinue() -} - -func editCompany(session *api.Session) { - ui.ClearScreen() - fmt.Println("Editing a company...") - // TODO: Implement company editing logic using the API - utils.PressEnterToContinue() -} - -func deleteCompany(session *api.Session) { - ui.ClearScreen() - fmt.Println("Deleting a company...") - // TODO: Implement company deletion logic using the API - utils.PressEnterToContinue() -} diff --git a/internal/handlers/cli/contacts.go b/internal/handlers/cli/contacts.go deleted file mode 100644 index ced6f97..0000000 --- a/internal/handlers/cli/contacts.go +++ /dev/null @@ -1,67 +0,0 @@ -package cli - -import ( - "fmt" - "marmic/servicetrade-toolbox/internal/api" - "marmic/servicetrade-toolbox/internal/ui" - "marmic/servicetrade-toolbox/internal/utils" -) - -func HandleContacts(session *api.Session) { - for { - ui.ClearScreen() - fmt.Println("Contacts Menu:") - fmt.Println("1. List Contacts") - fmt.Println("2. Add Contact") - fmt.Println("3. Edit Contact") - fmt.Println("4. Delete Contact") - fmt.Println("5. Back to Main Menu") - - choice, err := utils.GetUserChoice(5) - if err != nil { - ui.DisplayError("Invalid input:", err) - utils.PressEnterToContinue() - continue - } - switch choice { - case 1: - listContacts(session) - case 2: - addContact(session) - case 3: - editContact(session) - case 4: - deleteContact(session) - case 5: - return - } - } -} - -func listContacts(session *api.Session) { - ui.ClearScreen() - fmt.Println("Listing contacts...") - // TODO: Implement contact listing logic using the API - utils.PressEnterToContinue() -} - -func addContact(session *api.Session) { - ui.ClearScreen() - fmt.Println("Adding a new contact...") - // TODO: Implement contact creation logic using the API - utils.PressEnterToContinue() -} - -func editContact(session *api.Session) { - ui.ClearScreen() - fmt.Println("Editing a contact...") - // TODO: Implement contact editing logic using the API - utils.PressEnterToContinue() -} - -func deleteContact(session *api.Session) { - ui.ClearScreen() - fmt.Println("Deleting a contact...") - // TODO: Implement contact deletion logic using the API - utils.PressEnterToContinue() -} diff --git a/internal/handlers/cli/contracts.go b/internal/handlers/cli/contracts.go deleted file mode 100644 index 05c8e40..0000000 --- a/internal/handlers/cli/contracts.go +++ /dev/null @@ -1,67 +0,0 @@ -package cli - -import ( - "fmt" - "marmic/servicetrade-toolbox/internal/api" - "marmic/servicetrade-toolbox/internal/ui" - "marmic/servicetrade-toolbox/internal/utils" -) - -func HandleContracts(session *api.Session) { - for { - ui.ClearScreen() - fmt.Println("Contracts Menu:") - fmt.Println("1. List Contracts") - fmt.Println("2. Add Contract") - fmt.Println("3. Edit Contract") - fmt.Println("4. Delete Contract") - fmt.Println("5. Back to Main Menu") - - choice, err := utils.GetUserChoice(5) - if err != nil { - ui.DisplayError("Invalid input:", err) - utils.PressEnterToContinue() - continue - } - switch choice { - case 1: - listContracts(session) - case 2: - addContract(session) - case 3: - editContract(session) - case 4: - deleteContract(session) - case 5: - return - } - } -} - -func listContracts(session *api.Session) { - ui.ClearScreen() - fmt.Println("Listing contracts...") - // TODO: Implement contract listing logic using the API - utils.PressEnterToContinue() -} - -func addContract(session *api.Session) { - ui.ClearScreen() - fmt.Println("Adding a new contract...") - // TODO: Implement contract creation logic using the API - utils.PressEnterToContinue() -} - -func editContract(session *api.Session) { - ui.ClearScreen() - fmt.Println("Editing a contract...") - // TODO: Implement contract editing logic using the API - utils.PressEnterToContinue() -} - -func deleteContract(session *api.Session) { - ui.ClearScreen() - fmt.Println("Deleting a contract...") - // TODO: Implement contract deletion logic using the API - utils.PressEnterToContinue() -} diff --git a/internal/handlers/cli/generic.go b/internal/handlers/cli/generic.go deleted file mode 100644 index ef1bab0..0000000 --- a/internal/handlers/cli/generic.go +++ /dev/null @@ -1,57 +0,0 @@ -package cli - -import ( - "fmt" - "marmic/servicetrade-toolbox/internal/api" - "marmic/servicetrade-toolbox/internal/ui" - "marmic/servicetrade-toolbox/internal/utils" -) - -func HandleGenericTools(session *api.Session) { - for { - ui.ClearScreen() - fmt.Println("Generic Tools Menu:") - fmt.Println("1. Tool 1") - fmt.Println("2. Tool 2") - fmt.Println("3. Tool 3") - fmt.Println("4. Back to Main Menu") - - choice, err := utils.GetUserChoice(4) - if err != nil { - ui.DisplayError("Invalid input:", err) - utils.PressEnterToContinue() - continue - } - switch choice { - case 1: - runTool1(session) - case 2: - runTool2(session) - case 3: - runTool3(session) - case 4: - return - } - } -} - -func runTool1(session *api.Session) { - ui.ClearScreen() - fmt.Println("Running Tool 1...") - // TODO: Implement Tool 1 logic - utils.PressEnterToContinue() -} - -func runTool2(session *api.Session) { - ui.ClearScreen() - fmt.Println("Running Tool 2...") - // TODO: Implement Tool 2 logic - utils.PressEnterToContinue() -} - -func runTool3(session *api.Session) { - ui.ClearScreen() - fmt.Println("Running Tool 3...") - // TODO: Implement Tool 3 logic - utils.PressEnterToContinue() -} diff --git a/internal/handlers/cli/invoices.go b/internal/handlers/cli/invoices.go deleted file mode 100644 index 752ed07..0000000 --- a/internal/handlers/cli/invoices.go +++ /dev/null @@ -1,70 +0,0 @@ -package cli - -import ( - "fmt" - "marmic/servicetrade-toolbox/internal/api" - "marmic/servicetrade-toolbox/internal/ui" - "marmic/servicetrade-toolbox/internal/utils" -) - -func HandleInvoices(session *api.Session) { - for { - ui.ClearScreen() - fmt.Println("Invoices Menu:") - fmt.Println("1. Search Invoice") - fmt.Println("2. List Recent Invoices") - fmt.Println("3. Create Invoice") - fmt.Println("4. Back to Main Menu") - - choice, err := utils.GetUserChoice(4) - if err != nil { - ui.DisplayError("Invalid input:", err) - utils.PressEnterToContinue() - continue - } - switch choice { - case 1: - searchInvoice(session) - case 2: - listRecentInvoices(session) - case 3: - createInvoice(session) - case 4: - return - } - } -} - -func searchInvoice(session *api.Session) { - ui.ClearScreen() - fmt.Println("Search Invoice:") - identifier := utils.PromptForInput("Enter Invoice Number or ID: ") - - invoice, err := session.GetInvoice(identifier) - if err != nil { - fmt.Printf("Error fetching invoice: %v\n", err) - utils.PressEnterToContinue() - return - } - - fmt.Println("Invoice Details:") - fmt.Printf("Invoice Number: %v\n", invoice["invoiceNumber"]) - fmt.Printf("Total Price: $%v\n", invoice["totalPrice"]) - fmt.Printf("Status: %v\n", invoice["status"]) - - utils.PressEnterToContinue() -} - -func listRecentInvoices(session *api.Session) { - ui.ClearScreen() - fmt.Println("Listing recent invoices...") - // TODO: Implement recent invoices listing logic using the API - utils.PressEnterToContinue() -} - -func createInvoice(session *api.Session) { - ui.ClearScreen() - fmt.Println("Creating a new invoice...") - // TODO: Implement invoice creation logic using the API - utils.PressEnterToContinue() -} diff --git a/internal/handlers/cli/jobs.go b/internal/handlers/cli/jobs.go deleted file mode 100644 index a598e5c..0000000 --- a/internal/handlers/cli/jobs.go +++ /dev/null @@ -1,116 +0,0 @@ -package cli - -import ( - "fmt" - "marmic/servicetrade-toolbox/internal/api" - "marmic/servicetrade-toolbox/internal/ui" - "marmic/servicetrade-toolbox/internal/utils" -) - -func HandleJobs(session *api.Session) { - for { - ui.DisplayMenu([]string{ - "Search Job by ID", - "List Recent Jobs", - "Create New Job", - "Manage Job Attachments", - "View Deficiencies", - "Back to Main Menu", - }, "Jobs Menu") - - choice, err := utils.GetUserChoice(6) - if err != nil { - ui.DisplayError("Invalid input:", err) - utils.PressEnterToContinue() - continue - } - - switch choice { - case 1: - searchJobByID(session) - case 2: - listRecentJobs(session) - case 3: - createNewJob(session) - case 4: - manageJobAttachments(session) - case 5: - viewDeficiencyById(session) - case 6: - return - } - } -} - -func searchJobByID(session *api.Session) { - ui.ClearScreen() - ui.DisplayMessage("Search Job by ID:") - jobID := utils.PromptForInput("Enter Job ID: ") - - // TODO: Implement job search logic using the API - ui.DisplayMessage(fmt.Sprintf("Searching for job with ID: %s", jobID)) - utils.PressEnterToContinue() -} - -func listRecentJobs(session *api.Session) { - ui.ClearScreen() - ui.DisplayMessage("Listing recent jobs...") - // TODO: Implement recent jobs listing logic using the API - utils.PressEnterToContinue() -} - -func createNewJob(session *api.Session) { - ui.ClearScreen() - ui.DisplayMessage("Creating a new job...") - // TODO: Implement job creation logic using the API - utils.PressEnterToContinue() -} - -func manageJobAttachments(session *api.Session) { - ui.ClearScreen() - jobID := utils.PromptForInput("Enter Job ID: ") - - attachments, err := session.GetAttachmentsForJob(jobID) - if err != nil { - ui.DisplayError("Failed to retrieve attachments:", err) - utils.PressEnterToContinue() - return - } - - ui.DisplayMessage(fmt.Sprintf("Attachments for Job %s:", jobID)) - if dataMap, ok := attachments["data"].(map[string]interface{}); ok { - if attachmentsList, ok := dataMap["attachments"].([]interface{}); ok { - for i, attachment := range attachmentsList { - if att, ok := attachment.(map[string]interface{}); ok { - ui.DisplayMessage(fmt.Sprintf("%d. %s", i+1, att["fileName"])) - } - } - } - } - - // TODO: Implement attachment deletion logic - utils.PressEnterToContinue() -} - -func viewDeficiencyById(session *api.Session) { - ui.ClearScreen() - deficiencyID := utils.PromptForInput("Enter Deficiency ID: ") - - ui.DisplayMessage(fmt.Sprintf("Fetching information for Deficiency %s...", deficiencyID)) - - deficiencies, err := session.GetDeficiencyInfoForJob(deficiencyID) - if err != nil { - ui.DisplayError("Failed to retrieve deficiency information:", err) - utils.PressEnterToContinue() - return - } - - for _, deficiency := range deficiencies { - ui.DisplayMessage(fmt.Sprintf("ID: %v", deficiency["id"])) - ui.DisplayMessage(fmt.Sprintf("Description: %v", deficiency["description"])) - ui.DisplayMessage(fmt.Sprintf("Status: %v", deficiency["status"])) - ui.DisplayMessage("---") - } - - utils.PressEnterToContinue() -} diff --git a/internal/handlers/cli/locations.go b/internal/handlers/cli/locations.go deleted file mode 100644 index 4fec6db..0000000 --- a/internal/handlers/cli/locations.go +++ /dev/null @@ -1,67 +0,0 @@ -package cli - -import ( - "fmt" - "marmic/servicetrade-toolbox/internal/api" - "marmic/servicetrade-toolbox/internal/ui" - "marmic/servicetrade-toolbox/internal/utils" -) - -func HandleLocations(session *api.Session) { - for { - ui.ClearScreen() - fmt.Println("Locations Menu:") - fmt.Println("1. List Locations") - fmt.Println("2. Add Location") - fmt.Println("3. Edit Location") - fmt.Println("4. Delete Location") - fmt.Println("5. Back to Main Menu") - - choice, err := utils.GetUserChoice(5) - if err != nil { - ui.DisplayError("Invalid input:", err) - utils.PressEnterToContinue() - continue - } - switch choice { - case 1: - listLocations(session) - case 2: - addLocation(session) - case 3: - editLocation(session) - case 4: - deleteLocation(session) - case 5: - return - } - } -} - -func listLocations(session *api.Session) { - ui.ClearScreen() - fmt.Println("Listing locations...") - // TODO: Implement location listing logic using the API - utils.PressEnterToContinue() -} - -func addLocation(session *api.Session) { - ui.ClearScreen() - fmt.Println("Adding a new location...") - // TODO: Implement location creation logic using the API - utils.PressEnterToContinue() -} - -func editLocation(session *api.Session) { - ui.ClearScreen() - fmt.Println("Editing a location...") - // TODO: Implement location editing logic using the API - utils.PressEnterToContinue() -} - -func deleteLocation(session *api.Session) { - ui.ClearScreen() - fmt.Println("Deleting a location...") - // TODO: Implement location deletion logic using the API - utils.PressEnterToContinue() -} diff --git a/internal/handlers/cli/login.go b/internal/handlers/cli/login.go deleted file mode 100644 index 2cc253e..0000000 --- a/internal/handlers/cli/login.go +++ /dev/null @@ -1,104 +0,0 @@ -package cli - -import ( - "html/template" - "log" - "marmic/servicetrade-toolbox/internal/api" - "marmic/servicetrade-toolbox/internal/middleware" - "net/http" - "strings" -) - -func LoginHandler(w http.ResponseWriter, r *http.Request) { - if r.Method == "GET" { - tmpl := template.Must(template.ParseFiles("templates/login.html")) - tmpl.Execute(w, nil) - return - } - - if r.Method == "POST" { - email := r.FormValue("email") - password := r.FormValue("password") - - session := api.NewSession() - err := session.Login(email, password) - if err != nil { - if r.Header.Get("HX-Request") == "true" { - w.Write([]byte("