diff --git a/client/src/api/api.js b/client/src/api/api.js index cf8bd73..85c8536 100644 --- a/client/src/api/api.js +++ b/client/src/api/api.js @@ -1,5 +1,5 @@ import axios from "axios"; export default axios.create({ - baseURL: `http://localhost/`, + baseURL: `http://localhost:3000/api/`, }); diff --git a/client/src/api/reducers.js b/client/src/api/reducers.js new file mode 100644 index 0000000..410d99d --- /dev/null +++ b/client/src/api/reducers.js @@ -0,0 +1,61 @@ +import { + fields, + workLogFields, +} from "../components/form/ManageTicketForm/fields"; + +export const dataFetchReducer = (state, action) => { + switch (action.type) { + case "CLEAR_FORM": + const newData = state.data; + newData.map((o) => (o.value = "")); + return { + ...state, + data: newData, + }; + case "FETCH_INIT": + return { + ...state, + isLoading: true, + isError: false, + }; + case "FETCH_TICKET_SUCCESS": + return { + ...state, + isLoading: false, + isError: false, + data: action.payload, + }; + case "FETCH_TECHNICIANS_SUCCESS": + return { + ...state, + isLoading: false, + isError: false, + selectTechnicianOptions: action.payload, + }; + case "FETCH_FAILURE": + return { + ...state, + isLoading: false, + isError: true, + }; + case "UPDATE_DATA": + return { + ...state, + data: action.payload, + }; + case "FETCH_WORK_LOG_SUCCESS": + return { + ...state, + workLogData: action.payload, + workLogLoading: false, + }; + case "FETCH_ASSIGN_LOG_SUCCESS": + return { + ...state, + assignLogData: action.payload, + assignLogLoading: false, + }; + default: + throw new Error(); + } +}; diff --git a/client/src/components/app/app.js b/client/src/components/app/app.js index 23685f5..8920956 100644 --- a/client/src/components/app/app.js +++ b/client/src/components/app/app.js @@ -10,4 +10,4 @@ export const App = () => { ); }; -export const DEBUG_ON = true; +export const DEBUG_ON = false; diff --git a/client/src/components/callout/Callout.js b/client/src/components/callout/Callout.js new file mode 100644 index 0000000..d1dd503 --- /dev/null +++ b/client/src/components/callout/Callout.js @@ -0,0 +1,15 @@ +import React from "react"; + +import { EuiCallOut, EuiLink } from "@elastic/eui"; + +export const ErrorCallout = ({ errMsg }, ...props) => { + return ( + +

{errMsg}

+
+ ); +}; diff --git a/client/src/components/form/ManageTechnicianForm/NewTechnicianForm.js b/client/src/components/form/ManageTechnicianForm/NewTechnicianForm.js index 69309e9..1ec0e63 100644 --- a/client/src/components/form/ManageTechnicianForm/NewTechnicianForm.js +++ b/client/src/components/form/ManageTechnicianForm/NewTechnicianForm.js @@ -15,58 +15,61 @@ import { handleFormFieldBlur, handleFormFieldChange, } from "../ManageTicketForm/handlers"; +import { MySelectField } from "../MySelectField"; +import { selectOptions } from "../selectOptions"; var _ = require("lodash"); -export const NewTechnicianForm = ({ data, setData }, ...props) => { +export const NewTechnicianForm = ({ data, dispatch }, ...props) => { return ( <> handleFormFieldChange(e, data, setData)} - handleBlur={(e) => handleFormFieldBlur(e, data, setData)} + handleChange={(e) => handleFormFieldChange(e, data, dispatch)} + handleBlur={(e) => handleFormFieldBlur(e, data, dispatch)} /> handleFormFieldChange(e, data, setData)} - handleBlur={(e) => handleFormFieldBlur(e, data, setData)} + handleChange={(e) => handleFormFieldChange(e, data, dispatch)} + handleBlur={(e) => handleFormFieldBlur(e, data, dispatch)} /> handleFormFieldChange(e, data, setData)} - handleBlur={(e) => handleFormFieldBlur(e, data, setData)} + handleChange={(e) => handleFormFieldChange(e, data, dispatch)} + handleBlur={(e) => handleFormFieldBlur(e, data, dispatch)} /> - handleFormFieldChange(e, data, setData)} - handleBlur={(e) => handleFormFieldBlur(e, data, setData)} + selectOptions={selectOptions.find((o) => o.name === "department")} + handleChange={(e) => handleFormFieldChange(e, data, dispatch)} + handleBlur={(e) => handleFormFieldBlur(e, data, dispatch)} /> handleFormFieldChange(e, data, setData)} - handleBlur={(e) => handleFormFieldBlur(e, data, setData)} + handleChange={(e) => handleFormFieldChange(e, data, dispatch)} + handleBlur={(e) => handleFormFieldBlur(e, data, dispatch)} /> handleFormFieldChange(e, data, setData)} - handleBlur={(e) => handleFormFieldBlur(e, data, setData)} + handleChange={(e) => handleFormFieldChange(e, data, dispatch)} + handleBlur={(e) => handleFormFieldBlur(e, data, dispatch)} /> diff --git a/client/src/components/form/ManageTechnicianForm/fields.js b/client/src/components/form/ManageTechnicianForm/fields.js index d8f8980..e810d15 100644 --- a/client/src/components/form/ManageTechnicianForm/fields.js +++ b/client/src/components/form/ManageTechnicianForm/fields.js @@ -1,17 +1,16 @@ -export const selectOptions = [ +export const selectTechnicianOptions_default = [ { name: "technician", - options: [ - { value: "tech_a", text: "Tech A" }, - { value: "tech_b", text: "Tech B" }, - ], + options: [{ value: "", text: "" }], }, ]; + export const fields = [ { name: "technician", label: "Technician", - value: selectOptions.find((o) => o.name === "technician").options[0].value, + value: selectTechnicianOptions_default.find((o) => o.name === "technician") + .options[0].value, error: false, error_type: "required", }, diff --git a/client/src/components/form/ManageTicketForm/adminView.js b/client/src/components/form/ManageTicketForm/adminView.js index 7719a87..ebbd4a8 100644 --- a/client/src/components/form/ManageTicketForm/adminView.js +++ b/client/src/components/form/ManageTicketForm/adminView.js @@ -11,25 +11,53 @@ import { EuiTitle, } from "@elastic/eui"; import React, { useState } from "react"; -import { MyTextField } from "../MyTextField"; import { MySelectField } from "../MySelectField"; -import { addToast } from "../../toast"; -import { DEBUG } from "../../app/app"; -import { errorMessages } from "./fields"; +import { errorMessages, workLogFields } from "./fields"; import { handleDateChange, handleFormFieldBlur, handleFormFieldChange, + handleFormSubmit, } from "./handlers"; import { selectOptions } from "../selectOptions"; -import { MyDatePicker } from "../MyDatePicker"; -import { TicketAssignmentTable } from "../../table/assignedTo"; +import { WorkLogTable } from "../../table/WorkLogTable"; +import { TicketAssignmentTable } from "../../table/TicketAssignmentTable"; import { AddTechnicianPopover } from "../../popover/TechnicianPopover"; -import { TimeLogTable } from "../../table/TimeLogTable"; +import { MyDatePicker } from "../MyDatePicker"; var _ = require("lodash"); -export const AdminView = ({ data, setData }, ...props) => { +export const AdminView = ( + { + technician, + selectedTicket, + data, + dispatch, + workLogData, + workLogLoading, + assignLogData, + assignLogLoading, + assignmentRefresh, + setAssignmentRefresh, + workRefresh, + setWorkRefresh, + }, + ...props +) => { + const internalFormSubmit = async (e, data) => { + const d = []; + d.push({ name: "start_datetime", value: data[0].value }); + d.push({ name: "end_datetime", value: data[1].value }); + d.push({ name: "ticket_id", value: selectedTicket.ticket_id }); + d.push({ name: "lsu_id", value: technician[0].value }); + + const response = await handleFormSubmit(e, d, "/work"); + if (response != null) { + const w = !workRefresh; + setWorkRefresh(w); + } + }; + const [timeData, setTimeData] = useState(workLogFields); return ( <> @@ -41,18 +69,18 @@ export const AdminView = ({ data, setData }, ...props) => { handleFormFieldBlur(e, data, setData)} - handleChange={(e) => handleFormFieldChange(e, data, setData)} + selectOptions={selectOptions.find((o) => o.name === "core_issue")} + handleBlur={(e) => handleFormFieldBlur(e, data, dispatch)} + handleChange={(e) => handleFormFieldChange(e, data, dispatch)} /> handleFormFieldBlur(e, data, setData)} - handleChange={(e) => handleFormFieldChange(e, data, setData)} + selectOptions={selectOptions.find((o) => o.name === "component")} + handleBlur={(e) => handleFormFieldBlur(e, data, dispatch)} + handleChange={(e) => handleFormFieldChange(e, data, dispatch)} /> @@ -64,20 +92,21 @@ export const AdminView = ({ data, setData }, ...props) => { handleFormFieldChange(e, data, setData)} - onBlur={(e) => handleFormFieldBlur(e, data, setData)} + onChange={(e) => handleFormFieldChange(e, data, dispatch)} + onBlur={(e) => handleFormFieldBlur(e, data, dispatch)} + value={_.find(data, ["name", "description"]).value} /> @@ -93,9 +122,20 @@ export const AdminView = ({ data, setData }, ...props) => { <> - - - + {assignLogLoading === true ? null : ( + <> + + + + + )} @@ -105,19 +145,20 @@ export const AdminView = ({ data, setData }, ...props) => {

Work Log

- - + + {workLogLoading === true ? null : ( + + )} - - handleDateChange(date, "start_datetime", data, setData) + handleDateChange(date, "start_datetime", timeData, setTimeData) } /> @@ -125,18 +166,19 @@ export const AdminView = ({ data, setData }, ...props) => { handleFormFieldBlur(e, data, setData)} handleChange={(e) => - handleDateChange(e, "end_datetime", data, setData) + handleDateChange(e, "end_datetime", timeData, setTimeData) } /> - Add Time Entry + internalFormSubmit(e, timeData)}> + Add Time Entry + @@ -144,9 +186,9 @@ export const AdminView = ({ data, setData }, ...props) => { handleFormFieldChange(e, data, setData)} - handleBlur={(e) => handleFormFieldBlur(e, data, setData)} - selectOptions={selectOptions} + handleChange={(e) => handleFormFieldChange(e, data, dispatch)} + handleBlur={(e) => handleFormFieldBlur(e, data, dispatch)} + selectOptions={selectOptions.find((o) => o.name === "status")} data={data} name={"status"} /> diff --git a/client/src/components/form/ManageTicketForm/fields.js b/client/src/components/form/ManageTicketForm/fields.js index 641ad83..6713ab4 100644 --- a/client/src/components/form/ManageTicketForm/fields.js +++ b/client/src/components/form/ManageTicketForm/fields.js @@ -1,6 +1,10 @@ import { personFields } from "../person/fields"; import { selectOptions } from "../selectOptions"; +export const required_field_props = { + error: false, + error_type: "none", +}; export const fields = [ ...personFields, { @@ -77,15 +81,8 @@ export const fields = [ error_type: "none", }, { - name: "start_datetime", - label: "Start Datetime", - value: "", - error: false, - error_type: "none", - }, - { - name: "end_datetime", - label: "End Datetime", + name: "submission_date", + label: "Submission Date", value: "", error: false, error_type: "none", @@ -103,3 +100,20 @@ export const errorMessages = [ { error_type: "required", error_message: "This field is required." }, { error_type: "none", error_message: "" }, ]; + +export const workLogFields = [ + { + name: "start_datetime", + label: "Start Datetime", + value: "", + error: false, + error_type: "none", + }, + { + name: "end_datetime", + label: "End Datetime", + value: "", + error: false, + error_type: "none", + }, +]; diff --git a/client/src/components/form/ManageTicketForm/handlers.js b/client/src/components/form/ManageTicketForm/handlers.js index 58e6641..fa07521 100644 --- a/client/src/components/form/ManageTicketForm/handlers.js +++ b/client/src/components/form/ManageTicketForm/handlers.js @@ -1,23 +1,49 @@ import { addToast } from "../../toast"; +import axios from "../../../api/api"; var _ = require("lodash"); -export const handleFormSubmit = (e, data) => { +const postData = async (endpoint, data) => { + console.log(data); + const response = await axios.post(endpoint, data); + return response; +}; + +const putData = async (endpoint, data) => { + console.log(data); + const response = await axios.put(endpoint, data); + return response; +}; + +export const handleFormSubmit = async (e, data, endpoint, put) => { const errors = _.find(data, ["error", true]); if (errors === undefined) { - console.log(data); + let d = data.map((o) => ({ [o.name]: o.value })); + const dd = Object.assign({}, ...d); + + let response; + if (put === true) { + response = await putData(endpoint, dd); + } else { + response = await postData(endpoint, dd); + } + addToast({ - title: "Ticket Submitted!", + title: "Saved!", color: "success", }); + + return response; } else { addToast({ title: "Check Form for Errors", color: "danger", }); + + return null; } }; -export const handleFormFieldChange = (e, data, setData) => { +export const handleFormFieldChange = (e, data, dispatch) => { const target = e.target; const value = target.value; const name = target.name; @@ -26,8 +52,7 @@ export const handleFormFieldChange = (e, data, setData) => { const index = newData.findIndex((o) => o.name === name); newData[index].value = value; - - setData([...newData]); + dispatch({ type: "UPDATE_DATA", payload: newData }); }; export const handleDateChange = (date, name, data, setData) => { @@ -35,11 +60,10 @@ export const handleDateChange = (date, name, data, setData) => { const index = newData.findIndex((o) => o.name === name); newData[index].value = date.toJSON(); - - setData([...newData]); + setData(newData); }; -export const handleFormFieldBlur = (e, data, setData) => { +export const handleFormFieldBlur = (e, data, dispatch) => { const name = e.target.name; const value = e.target.value; @@ -53,5 +77,5 @@ export const handleFormFieldBlur = (e, data, setData) => { newData[index].error = false; } - setData([...newData]); + dispatch({ type: "UPDATE_DATA", payload: newData }); }; diff --git a/client/src/components/form/ManageTicketForm/userView.js b/client/src/components/form/ManageTicketForm/userView.js index 2cff176..9a5e884 100644 --- a/client/src/components/form/ManageTicketForm/userView.js +++ b/client/src/components/form/ManageTicketForm/userView.js @@ -20,7 +20,7 @@ import { selectOptions } from "../selectOptions"; var _ = require("lodash"); -export const UserView = ({ data, setData }, ...props) => { +export const UserView = ({ data, dispatch }, ...props) => { return ( <> @@ -28,32 +28,33 @@ export const UserView = ({ data, setData }, ...props) => { handleFormFieldChange(e, data, setData)} - handleBlur={(e) => handleFormFieldBlur(e, data, setData)} + handleChange={(e) => handleFormFieldChange(e, data, dispatch)} + handleBlur={(e) => handleFormFieldBlur(e, data, dispatch)} /> handleFormFieldChange(e, data, setData)} - handleBlur={(e) => handleFormFieldBlur(e, data, setData)} + handleChange={(e) => handleFormFieldChange(e, data, dispatch)} + handleBlur={(e) => handleFormFieldBlur(e, data, dispatch)} /> handleFormFieldChange(e, data, setData)} - handleBlur={(e) => handleFormFieldBlur(e, data, setData)} + handleChange={(e) => handleFormFieldChange(e, data, dispatch)} + handleBlur={(e) => handleFormFieldBlur(e, data, dispatch)} /> - handleFormFieldChange(e, data, setData)} - handleBlur={(e) => handleFormFieldBlur(e, data, setData)} + selectOptions={selectOptions.find((o) => o.name === "department")} + handleChange={(e) => handleFormFieldChange(e, data, dispatch)} + handleBlur={(e) => handleFormFieldBlur(e, data, dispatch)} />
@@ -62,16 +63,16 @@ export const UserView = ({ data, setData }, ...props) => { handleFormFieldChange(e, data, setData)} - handleBlur={(e) => handleFormFieldBlur(e, data, setData)} + handleChange={(e) => handleFormFieldChange(e, data, dispatch)} + handleBlur={(e) => handleFormFieldBlur(e, data, dispatch)} /> handleFormFieldChange(e, data, setData)} - handleBlur={(e) => handleFormFieldBlur(e, data, setData)} + handleChange={(e) => handleFormFieldChange(e, data, dispatch)} + handleBlur={(e) => handleFormFieldBlur(e, data, dispatch)} /> @@ -84,9 +85,9 @@ export const UserView = ({ data, setData }, ...props) => { handleFormFieldChange(e, data, setData)} - handleBlur={(e) => handleFormFieldBlur(e, data, setData)} + selectOptions={selectOptions.find((o) => o.name === "priority")} + handleChange={(e) => handleFormFieldChange(e, data, dispatch)} + handleBlur={(e) => handleFormFieldBlur(e, data, dispatch)} /> @@ -95,32 +96,32 @@ export const UserView = ({ data, setData }, ...props) => { handleFormFieldChange(e, data, setData)} - handleBlur={(e) => handleFormFieldBlur(e, data, setData)} + handleChange={(e) => handleFormFieldChange(e, data, dispatch)} + handleBlur={(e) => handleFormFieldBlur(e, data, dispatch)} /> handleFormFieldChange(e, data, setData)} - handleBlur={(e) => handleFormFieldBlur(e, data, setData)} + handleChange={(e) => handleFormFieldChange(e, data, dispatch)} + handleBlur={(e) => handleFormFieldBlur(e, data, dispatch)} /> handleFormFieldChange(e, data, setData)} - handleBlur={(e) => handleFormFieldBlur(e, data, setData)} + handleChange={(e) => handleFormFieldChange(e, data, dispatch)} + handleBlur={(e) => handleFormFieldBlur(e, data, dispatch)} /> handleFormFieldChange(e, data, setData)} - handleBlur={(e) => handleFormFieldBlur(e, data, setData)} + handleChange={(e) => handleFormFieldChange(e, data, dispatch)} + handleBlur={(e) => handleFormFieldBlur(e, data, dispatch)} /> @@ -133,9 +134,11 @@ export const UserView = ({ data, setData }, ...props) => { handleFormFieldChange(e, data, setData)} - selectOptions={selectOptions} - handleBlur={(e) => handleFormFieldBlur(e, data, setData)} + handleChange={(e) => handleFormFieldChange(e, data, dispatch)} + selectOptions={selectOptions.find( + (o) => o.name === "problem_category" + )} + handleBlur={(e) => handleFormFieldBlur(e, data, dispatch)} /> @@ -154,8 +157,9 @@ export const UserView = ({ data, setData }, ...props) => { handleFormFieldChange(e, data, setData)} - onBlur={(e) => handleFormFieldBlur(e, data, setData)} + onChange={(e) => handleFormFieldChange(e, data, dispatch)} + onBlur={(e) => handleFormFieldBlur(e, data, dispatch)} + value={_.find(data, ["name", "description"]).value} /> diff --git a/client/src/components/form/MySelectField.js b/client/src/components/form/MySelectField.js index 771d12b..0fc85e9 100644 --- a/client/src/components/form/MySelectField.js +++ b/client/src/components/form/MySelectField.js @@ -13,10 +13,11 @@ export const MySelectField = ( o.name === name).options} - value={item.value} + options={selectOptions.options} + value={item.value === null ? "" : item.value} onChange={(e) => handleChange(e)} onBlur={(e) => handleBlur(e)} + hasNoInitialSelection={true} /> ); diff --git a/client/src/components/form/MyTextField.js b/client/src/components/form/MyTextField.js index c4f2e32..497ee27 100644 --- a/client/src/components/form/MyTextField.js +++ b/client/src/components/form/MyTextField.js @@ -20,6 +20,7 @@ export const MyTextField = ( name={item.name} onChange={(e) => handleChange(e)} onBlur={(e) => handleBlur(e)} + value={item.value} /> ); diff --git a/client/src/components/form/person/fields.js b/client/src/components/form/person/fields.js index b35683b..b735de7 100644 --- a/client/src/components/form/person/fields.js +++ b/client/src/components/form/person/fields.js @@ -22,14 +22,6 @@ export const personFields = [ error: false, error_type: "required", }, - { - name: "department", - label: "Department/College", - value: selectOptions.find((o) => o.name === "department").options[0].value, - error: false, - error_type: "required", - }, - { name: "email", label: "Email Address", @@ -44,4 +36,18 @@ export const personFields = [ error: false, error_type: "required", }, + { + name: "department", + label: "Department/College", + value: selectOptions.find((o) => o.name === "department").options[0].value, + error: false, + error_type: "required", + }, + { + name: "admin", + label: "Admin", + value: false, + error: false, + error_type: "required", + }, ]; diff --git a/client/src/components/form/selectOptions.js b/client/src/components/form/selectOptions.js index 1179135..2ffe608 100644 --- a/client/src/components/form/selectOptions.js +++ b/client/src/components/form/selectOptions.js @@ -2,24 +2,262 @@ export const selectOptions = [ { name: "priority", options: [ - { value: "low", text: "Low" }, - { value: "medium", text: "Medium" }, - { value: "high", text: "High" }, + { value: "", text: "" }, + { value: "1", text: "Low" }, + { value: "2", text: "Medium" }, + { value: "3", text: "High" }, ], }, { name: "problem_category", options: [ + { value: "", text: "" }, + { value: "general_help", text: "General Help" }, - { value: "problem_2", text: "Problem 2" }, + { value: "login_help", text: "Login Help" }, + { value: "missing_documents", text: "Missing Documents" }, + { value: "class_access", text: "Can't access your class?" }, + { value: "view_grades_help", text: "Can't see your grades?" }, + { value: "upload_help", text: "Upload Help" }, + { value: "download_help", text: "Download Help" }, + { value: "tigerware_support", text: "Tigerware support" }, + { value: "hardware_support", text: "Hardware support" }, ], }, { name: "department", options: [ - { value: "computer_science", text: "Computer Science" }, - { value: "petroleum_engineering", text: "Petroleum Engineering" }, - { value: "chemical_engineering", text: "Chemical Engineering" }, + { value: "", text: "" }, + { value: "accounting", text: "Accounting" }, + { + value: "administrative_foundation_se", + text: "Administrative_Foundation_Se", + }, + { value: "aerospace_studies", text: "Aerospace_Studies" }, + { + value: "african_african-american_stu", + text: "African_African-American_Stu", + }, + { value: "agric_education", text: "Agric_Education" }, + { + value: "agric_extension_ed_evaluat", + text: "Agric_Extension_Ed_Evaluat", + }, + { value: "agricultural_economics", text: "Agricultural_Economics" }, + { + value: "agricultural_economics_agrib", + text: "Agricultural_Economics_Agrib", + }, + { value: "agriculture", text: "Agriculture" }, + { + value: "agri,_extension_adult_educat", + text: "Agri,_Extension_Adult_Educat", + }, + { value: "agronomy", text: "Agronomy" }, + { value: "animal_sciences", text: "Animal_Sciences" }, + { value: "anthropology", text: "Anthropology" }, + { value: "arabic", text: "Arabic" }, + { value: "architecture", text: "Architecture" }, + { value: "art", text: "Art" }, + { value: "art_history", text: "Art_History" }, + { value: "astronomy", text: "Astronomy" }, + { value: "athletic_training", text: "Athletic_Training" }, + { value: "audio-visual_arts", text: "Audio-Visual_Arts" }, + { value: "basic_sciences", text: "Basic_Sciences" }, + { value: "biological_engineering", text: "Biological_Engineering" }, + { value: "biological_sciences", text: "Biological_Sciences" }, + { value: "business_administration", text: "Business_Administration" }, + { value: "business_education", text: "Business_Education" }, + { value: "business_law", text: "Business_Law" }, + { value: "chemical_engineering", text: "Chemical_Engineering" }, + { value: "chemistry", text: "Chemistry" }, + { value: "child_and_family_studies", text: "Child_And_Family_Studies" }, + { value: "chinese", text: "Chinese" }, + { value: "civil_engineering", text: "Civil_Engineering" }, + { + value: "civil_environmental_engineer", + text: "Civil_Environmental_Engineer", + }, + { value: "classical_studies", text: "Classical_Studies" }, + { value: "communication_disorders", text: "Communication_Disorders" }, + { value: "communication_studies", text: "Communication_Studies" }, + { + value: "comparative_biomedical_science", + text: "Comparative_Biomedical_Science", + }, + { value: "comparative_literature", text: "Comparative_Literature" }, + { value: "computer_science", text: "Computer_Science" }, + { value: "construction_management", text: "Construction_Management" }, + { value: "curriculum_instruction", text: "Curriculum_Instruction" }, + { value: "dairy_science", text: "Dairy_Science" }, + { + value: "digital_media_arts_engineeri", + text: "Digital_Media_Arts_Engineeri", + }, + { + value: "disaster_science_management", + text: "Disaster_Science_Management", + }, + { value: "doctor_of_design", text: "Doctor_Of_Design" }, + { value: "economics", text: "Economics" }, + { + value: "educ_leadership_research_couns", + text: "Educ_Leadership_Research_Couns", + }, + { value: "education", text: "Education" }, + { value: "electrical_engineering", text: "Electrical_Engineering" }, + { value: "engineering", text: "Engineering" }, + { value: "english", text: "English" }, + { value: "entomology", text: "Entomology" }, + { value: "entrepreneurship", text: "Entrepreneurship" }, + { value: "environmental_engineering", text: "Environmental_Engineering" }, + { + value: "environmental_management_systems", + text: "Environmental_Management_Systems", + }, + { value: "environmental_sciences", text: "Environmental_Sciences" }, + { value: "environmental_studies", text: "Environmental_Studies" }, + { + value: "epidemiology_community_health", + text: "Epidemiology_Community_Health", + }, + { value: "experimental_statistics", text: "Experimental_Statistics" }, + { value: "extension_education", text: "Extension_Education" }, + { value: "film_media_arts", text: "Film_Media_Arts" }, + { value: "finance", text: "Finance" }, + { value: "fisheries", text: "Fisheries" }, + { value: "food_science", text: "Food_Science" }, + { value: "forestry", text: "Forestry" }, + { value: "french", text: "French" }, + { value: "french_studies", text: "French_Studies" }, + { value: "freshman_forum", text: "Freshman_Forum" }, + { value: "freshman_seminar", text: "Freshman_Seminar" }, + { value: "general_business", text: "General_Business" }, + { value: "geography", text: "Geography" }, + { value: "geology", text: "Geology" }, + { value: "german", text: "German" }, + { value: "greek", text: "Greek" }, + { value: "hebrew", text: "Hebrew" }, + { value: "history", text: "History" }, + { value: "home_econ_educ", text: "Home_Econ_Educ" }, + { value: "honors", text: "Honors" }, + { value: "horticulture", text: "Horticulture" }, + { value: "how_to_do_lsu", text: "How_To_Do_Lsu" }, + { value: "human_ecology", text: "Human_Ecology" }, + { value: "human_resource_education", text: "Human_Resource_Education" }, + { value: "human_sciences_education", text: "Human_Sciences_Education" }, + { value: "humanities", text: "Humanities" }, + { + value: "humanities_and_social_sciences", + text: "Humanities_And_Social_Sciences", + }, + { value: "industrial_education", text: "Industrial_Education" }, + { value: "industrial_engineering", text: "Industrial_Engineering" }, + { value: "industrial_technology", text: "Industrial_Technology" }, + { + value: "industrial_manufacture_engineering", + text: "Industrial_Manufacture_Engineering", + }, + { + value: "info_systems_and_decision_science", + text: "Info_Systems_And_Decision_Science", + }, + { value: "interior_design", text: "Interior_Design" }, + { value: "international_studies", text: "International_Studies" }, + { value: "italian", text: "Italian" }, + { value: "japanese", text: "Japanese" }, + { value: "junior_division", text: "Junior_Division" }, + { value: "kinesiology", text: "Kinesiology" }, + { value: "landscape_architecture", text: "Landscape_Architecture" }, + { value: "latin", text: "Latin" }, + { + value: "leadership_human_resources_d", + text: "Leadership_Human_Resources_D", + }, + { value: "liberal_arts", text: "Liberal_Arts" }, + { + value: "library_information_science", + text: "Library_Information_Science", + }, + { value: "life_course_and_aging", text: "Life_Course_And_Aging" }, + { value: "life_course_in_aging", text: "Life_Course_In_Aging" }, + { value: "linguistics", text: "Linguistics" }, + { value: "management", text: "Management" }, + { value: "marketing", text: "Marketing" }, + { value: "mass_communication", text: "Mass_Communication" }, + { value: "mathematics", text: "Mathematics" }, + { value: "mechanical_engineering", text: "Mechanical_Engineering" }, + { value: "medical_physics", text: "Medical_Physics" }, + { value: "military_science", text: "Military_Science" }, + { value: "music", text: "Music" }, + { value: "music_education", text: "Music_Education" }, + { value: "nuclear_science", text: "Nuclear_Science" }, + { value: "nutrition_food_sciences", text: "Nutrition_Food_Sciences" }, + { + value: "oceanography_coastal_science", + text: "Oceanography_Coastal_Science", + }, + { value: "pathobiological_sciences", text: "Pathobiological_Sciences" }, + { value: "petroleum_engineering", text: "Petroleum_Engineering" }, + { value: "philosophy", text: "Philosophy" }, + { + value: "philosophy_religious_studies", + text: "Philosophy_Religious_Studies", + }, + { value: "physical_science", text: "Physical_Science" }, + { value: "physics", text: "Physics" }, + { value: "plant_health", text: "Plant_Health" }, + { value: "political_science", text: "Political_Science" }, + { value: "portuguese", text: "Portuguese" }, + { value: "poultry_science", text: "Poultry_Science" }, + { value: "psychology", text: "Psychology" }, + { value: "public_administration", text: "Public_Administration" }, + { value: "religious_studies", text: "Religious_Studies" }, + { + value: "renewable_natural_resources", + text: "Renewable_Natural_Resources", + }, + { value: "russian", text: "Russian" }, + { value: "science", text: "Science" }, + { value: "screen_arts", text: "Screen_Arts" }, + { value: "social_work", text: "Social_Work" }, + { value: "sociology", text: "Sociology" }, + { value: "spanish", text: "Spanish" }, + { value: "speech_communication", text: "Speech_Communication" }, + { value: "student_support_services", text: "Student_Support_Services" }, + { value: "swahili", text: "Swahili" }, + { value: "systems_science", text: "Systems_Science" }, + { + value: "textiles,apparel_merchandise", + text: "Textiles,Apparel_Merchandise", + }, + { value: "theatre", text: "Theatre" }, + { value: "university", text: "University" }, + { value: "university_college", text: "University_College" }, + { value: "university_studies", text: "University_Studies" }, + { value: "veterinary_anatomy", text: "Veterinary_Anatomy" }, + { + value: "veterinary_clinical_sciences", + text: "Veterinary_Clinical_Sciences", + }, + { value: "veterinary_medicine", text: "Veterinary_Medicine" }, + { + value: "veterinary_microbiol_parasit", + text: "Veterinary_Microbiol_Parasit", + }, + { value: "veterinary_pathology", text: "Veterinary_Pathology" }, + { + value: "veterinary_physiol,_pharmacy", + text: "VeterinaryPhysiol Pharmacy", + }, + { value: "veterinary_science", text: "Veterinary Science" }, + { value: "vocational_education", text: "Vocational Education" }, + { value: "vocational_trade_ind_ed", text: "Vocational Trade Ind Ed" }, + { value: "wildlife", text: "Wildlife" }, + { + value: "women's_and_gender_studies", + text: "Women'S_And_Gender_Studies", + }, ], }, { @@ -28,6 +266,11 @@ export const selectOptions = [ { value: "broken_screen", text: "Broken Screen" }, { value: "expanded_battery", text: "Expanded Battery" }, { value: "faulty_ram", text: "Faulty RAM" }, + { value: "network_problem", text: "Network Problem" }, + { value: "post_error", text: "Post Error" }, + { value: "virus_infection", text: "Malware or Spyware Infection" }, + { value: "system_overheat", text: "System overheating" }, + { value: "system_crash", text: "System Crash" }, ], }, { @@ -39,6 +282,10 @@ export const selectOptions = [ { value: "storage_device", text: "Storage Device" }, { value: "power_supply", text: "Power Supply" }, { value: "gpu", text: "GPU" }, + { value: "motherboard", text: "Motherboard" }, + { value: "heatsink", text: "Heatsink" }, + { value: "case_fans", text: "Case Fans" }, + { value: "usb_port", text: "USB Port" }, ], }, { diff --git a/client/src/components/popover/TechnicianPopover.js b/client/src/components/popover/TechnicianPopover.js index 5a34d9e..820b794 100644 --- a/client/src/components/popover/TechnicianPopover.js +++ b/client/src/components/popover/TechnicianPopover.js @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useEffect, useReducer, useState } from "react"; import { EuiButton, @@ -9,20 +9,66 @@ import { EuiFlexItem, } from "@elastic/eui"; import { MySelectField } from "../form/MySelectField"; -import { fields, selectOptions } from "../form/ManageTechnicianForm/fields"; +import { + fields, + selectTechnicianOptions_default, +} from "../form/ManageTechnicianForm/fields"; import { handleFormFieldBlur, handleFormFieldChange, + handleFormSubmit, } from "../form/ManageTicketForm/handlers"; +import { dataFetchReducer } from "../../api/reducers"; +import axios from "../../api/api"; +import { personFields } from "../form/person/fields"; -export const AddTechnicianPopover = () => { - const [data, setData] = useState(fields); +export const AddTechnicianPopover = ( + { selectedTicket, assignmentRefresh, setAssignmentRefresh }, + ...props +) => { + const [state, dispatch] = useReducer(dataFetchReducer, { + isLoading: false, + isError: false, + data: fields, + selectTechnicianOptions: selectTechnicianOptions_default, + }); const [isPopoverOpen, setIsPopoverOpen] = useState(false); + useEffect(() => { + const fetchData = async () => { + dispatch({ type: "FETCH_INIT" }); + try { + const result = await axios.get("/user/admin"); + const final = { + name: "technician", + options: result.data.map((o) => ({ + ...o, + value: o.lsu_id, + text: o.first_name + " " + o.last_name, + })), + }; + dispatch({ type: "FETCH_TECHNICIANS_SUCCESS", payload: final }); + } catch (error) { + dispatch({ type: "FETCH_FAILURE" }); + } + }; + fetchData(); + }, []); const onButtonClick = () => setIsPopoverOpen((isPopoverOpen) => !isPopoverOpen); const closePopover = () => setIsPopoverOpen(false); + const internalFormSubmit = async (e, data) => { + const d = []; + d.push({ name: "lsu_id", value: data[0].value }); + d.push({ name: "ticket_id", value: selectedTicket.ticket_id }); + + const response = await handleFormSubmit(e, d, "/assign"); + if (response != null) { + setIsPopoverOpen(false); + setAssignmentRefresh(!assignmentRefresh); + } + }; const button = ( Add @@ -30,29 +76,39 @@ export const AddTechnicianPopover = () => { ); return ( - -
- - - handleFormFieldChange(e, data, setData)} - handleBlur={(e) => handleFormFieldBlur(e, data, setData)} - /> - - - - Add - - - -
-
+ <> + {state.isLoading === true ? null : ( + + + + + { + handleFormFieldChange(e, state.data, dispatch); + }} + handleBlur={(e) => + handleFormFieldBlur(e, state.data, dispatch) + } + /> + + + + internalFormSubmit(e, state.data)}> + Add + + + + + + + )} + ); }; diff --git a/client/src/components/table/assignedTo.js b/client/src/components/table/TicketAssignmentTable.js similarity index 55% rename from client/src/components/table/assignedTo.js rename to client/src/components/table/TicketAssignmentTable.js index 48af5cb..cd5b103 100644 --- a/client/src/components/table/assignedTo.js +++ b/client/src/components/table/TicketAssignmentTable.js @@ -3,28 +3,7 @@ import React from "react"; import { EuiBasicTable, EuiLink, EuiHealth, EuiButton } from "@elastic/eui"; import { AdminTicketFlyout } from "../flyout/flyout"; -const userTest = [ - { - id: "1", - firstName: "john", - lastName: "doe", - }, -]; -/* -Example user object: - - - -Example country object: - -{ - code: 'NL', - name: 'Netherlands', - flag: '🇳🇱' -} -*/ - -export const TicketAssignmentTable = ({ handleTicketSelection }, ...props) => { +export const TicketAssignmentTable = ({ items, isLoading }, ...props) => { const deleteUser = (user) => {}; const actions = [ @@ -41,18 +20,12 @@ export const TicketAssignmentTable = ({ handleTicketSelection }, ...props) => { const columns = [ { - field: "firstName", + field: "first_name", name: "First Name", - sortable: true, - "data-test-subj": "firstNameCell", }, { - field: "lastName", + field: "last_name", name: "Last Name", - truncateText: true, - mobileOptions: { - show: false, - }, }, { name: "Actions", @@ -60,16 +33,14 @@ export const TicketAssignmentTable = ({ handleTicketSelection }, ...props) => { }, ]; - const items = userTest.filter((user, index) => index < 10); - const getRowProps = (item) => { const { id } = item; return { "data-test-subj": `row-${id}`, className: "customRowClass", - onClick: (e) => { - handleTicketSelection(e, id); - }, + // onClick: (e) => { + // handleTicketSelection(e, id); + // }, }; }; @@ -84,12 +55,17 @@ export const TicketAssignmentTable = ({ handleTicketSelection }, ...props) => { }; return ( - +
+ {isLoading === true ? null : ( + + )} +
); }; diff --git a/client/src/components/table/TicketsTable.js b/client/src/components/table/TicketsTable.js new file mode 100644 index 0000000..35aa608 --- /dev/null +++ b/client/src/components/table/TicketsTable.js @@ -0,0 +1,111 @@ +import React, { useEffect, useState, useReducer } from "react"; +import axios from "../../api/api"; +import { EuiBasicTable, EuiLink, EuiHealth, EuiButton } from "@elastic/eui"; +import { AdminTicketFlyout } from "../flyout/flyout"; +import { dataFetchReducer } from "../../api/reducers"; +import { ErrorCallout } from "../callout/Callout"; + +export const TicketsTable = ( + { handleTicketSelection, tickets, isLoading }, + ...props +) => { + const columns = [ + { + field: "first_name", + name: "First Name", + sortable: true, + "data-test-subj": "firstNameCell", + mobileOptions: { + render: (item) => ( + + {item.firstName}{" "} + + {item.lastName} + + + ), + header: false, + truncateText: false, + enlarge: true, + fullWidth: true, + }, + }, + { + field: "last_name", + name: "Last Name", + truncateText: true, + }, + { + field: "lsu_id", + name: "LSU ID", + }, + { + field: "problem_category", + name: "Problem Category", + render: (problem_category) => { + String.prototype.toProperCase = function () { + return this.replace(/\w\S*/g, function (txt) { + return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); + }); + }; + + return problem_category.replace("_", " ").toProperCase(); + }, + }, + { + field: "status", + name: "Status", + render: (status) => { + const color = + status === "OPEN" + ? "danger" + : status === "IN PROGRESS" + ? "primary" + : "success"; + const label = + status === "OPEN" + ? "Open" + : status === "IN PROGRESS" + ? "In Progress" + : "Closed"; + return {label}; + }, + }, + ]; + + const getRowProps = (item) => { + const { lsu_id } = item; + return { + "data-test-subj": `row-${lsu_id}`, + className: "customRowClass", + onClick: (e) => { + handleTicketSelection(e, item); + }, + }; + }; + + const getCellProps = (item, column) => { + const { id } = item; + const { field } = column; + return { + className: "customCellClass", + "data-test-subj": `cell-${id}-${field}`, + textOnly: true, + }; + }; + + return ( +
+ {isLoading === true ? null : ( + + )} +
+ ); +}; diff --git a/client/src/components/table/TimeLogTable.js b/client/src/components/table/WorkLogTable.js similarity index 56% rename from client/src/components/table/TimeLogTable.js rename to client/src/components/table/WorkLogTable.js index 71d6e97..8114742 100644 --- a/client/src/components/table/TimeLogTable.js +++ b/client/src/components/table/WorkLogTable.js @@ -2,29 +2,9 @@ import React from "react"; import { EuiBasicTable, EuiLink, EuiHealth, EuiButton } from "@elastic/eui"; import { AdminTicketFlyout } from "../flyout/flyout"; +import moment from "moment"; -const userTest = [ - { - id: "1", - start_datetime: "john", - end_datetime: "doe", - }, -]; -/* -Example user object: - - - -Example country object: - -{ - code: 'NL', - name: 'Netherlands', - flag: '🇳🇱' -} -*/ - -export const TimeLogTable = ({ handleTicketSelection }, ...props) => { +export const WorkLogTable = ({ items, isLoading }, ...props) => { const deleteUser = (user) => {}; const actions = [ @@ -40,18 +20,26 @@ export const TimeLogTable = ({ handleTicketSelection }, ...props) => { ]; const columns = [ + { + field: "first_name", + name: "First Name", + }, + { + field: "last_name", + name: "Last Name", + }, { field: "start_datetime", name: "Start Datetime", - sortable: true, - "data-test-subj": "firstNameCell", + render: (start_datetime) => { + return moment(start_datetime).format("MMMM Do YYYY, h:mm a"); + }, }, { field: "end_datetime", name: "End Datetime", - truncateText: true, - mobileOptions: { - show: false, + render: (end_datetime) => { + return moment(end_datetime).format("MMMM Do YYYY, h:mm a"); }, }, { @@ -60,16 +48,14 @@ export const TimeLogTable = ({ handleTicketSelection }, ...props) => { }, ]; - const items = userTest.filter((user, index) => index < 10); - const getRowProps = (item) => { const { id } = item; return { "data-test-subj": `row-${id}`, className: "customRowClass", - onClick: (e) => { - handleTicketSelection(e, id); - }, + // onClick: (e) => { + // handleTicketSelection(e, id); + // }, }; }; @@ -84,12 +70,17 @@ export const TimeLogTable = ({ handleTicketSelection }, ...props) => { }; return ( - +
+ {isLoading === true ? null : ( + + )} +
); }; diff --git a/client/src/components/table/openTickets.js b/client/src/components/table/openTickets.js deleted file mode 100644 index 5710389..0000000 --- a/client/src/components/table/openTickets.js +++ /dev/null @@ -1,114 +0,0 @@ -import React from "react"; - -import { EuiBasicTable, EuiLink, EuiHealth, EuiButton } from "@elastic/eui"; -import { AdminTicketFlyout } from "../flyout/flyout"; - -const userTest = [ - { - id: "1", - firstName: "john", - lastName: "doe", - github: "johndoe", - dateOfBirth: Date.now(), - nationality: "NL", - online: true, - }, -]; -/* -Example user object: - - - -Example country object: - -{ - code: 'NL', - name: 'Netherlands', - flag: '🇳🇱' -} -*/ - -export const TicketsTable = ({ handleTicketSelection }, ...props) => { - const columns = [ - { - field: "firstName", - name: "First Name", - sortable: true, - "data-test-subj": "firstNameCell", - mobileOptions: { - render: (item) => ( - - {item.firstName}{" "} - - {item.lastName} - - - ), - header: false, - truncateText: false, - enlarge: true, - fullWidth: true, - }, - }, - { - field: "lastName", - name: "Last Name", - truncateText: true, - render: (name) => ( - - {name} - - ), - mobileOptions: { - show: false, - }, - }, - { - field: "github", - name: "Github", - }, - { - field: "online", - name: "Online", - dataType: "boolean", - render: (online) => { - const color = online ? "success" : "danger"; - const label = online ? "Online" : "Offline"; - return {label}; - }, - }, - ]; - - const items = userTest.filter((user, index) => index < 10); - - const getRowProps = (item) => { - const { id } = item; - return { - "data-test-subj": `row-${id}`, - className: "customRowClass", - onClick: (e) => { - handleTicketSelection(e, id); - }, - }; - }; - - const getCellProps = (item, column) => { - const { id } = item; - const { field } = column; - return { - className: "customCellClass", - "data-test-subj": `cell-${id}-${field}`, - textOnly: true, - }; - }; - - return ( - - ); -}; diff --git a/client/src/routes/admin/ManageTicket.js b/client/src/routes/admin/ManageTicket.js index d8b282c..40b09f0 100644 --- a/client/src/routes/admin/ManageTicket.js +++ b/client/src/routes/admin/ManageTicket.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from "react"; +import React, { useState, useEffect, useReducer } from "react"; import { EuiPage, @@ -21,52 +21,195 @@ import { EuiCode, } from "@elastic/eui"; import { NavBar } from "../../components/navbar/navbar"; -import { TicketsTable } from "../../components/table/openTickets"; +import { TicketsTable } from "../../components/table/TicketsTable"; import { AdminTicketFlyout } from "../../components/flyout/flyout"; import { UserView } from "../../components/form/ManageTicketForm/userView"; import { handleFormSubmit } from "../../components/form/ManageTicketForm/handlers"; import { AdminView } from "../../components/form/ManageTicketForm/adminView"; import { Debug } from "../../components/debug/debug"; import axios from "../../api/api"; -import { fields } from "../../components/form/ManageTicketForm/fields"; +import { + fields, + workLogFields, +} from "../../components/form/ManageTicketForm/fields"; +import { dataFetchReducer } from "../../api/reducers"; +import { MyStat } from "./Stats"; +import { personFields } from "../../components/form/person/fields"; + var _ = require("lodash"); -const TicketForm = ({ data, setData }, ...props) => { +const TicketForm = ( + { technician, setSelectedTicket, selectedTicket }, + ...props +) => { + const [state, dispatch] = useReducer(dataFetchReducer, { + isLoading: false, + isError: false, + data: fields, + workLogData: null, + workLogLoading: true, + assignLog: null, + assignLogLoading: true, + }); + + const [workRefresh, setWorkRefresh] = useState(false); + const [assignmentRefresh, setAssignmentRefresh] = useState(false); + const [dataRefresh, setDataRefresh] = useState(false); + + useEffect(() => { + const fetchWorkLog = async (selectedTicket) => { + try { + const result = await axios.get( + "/work/ticket/" + selectedTicket.ticket_id + ); + const userResult = await axios.get("/user/admin"); + let final = []; + + for (let i = 0; i < result.data.length; i++) { + final.push({ + ...result.data[i], + ...userResult.data.find( + (itmInner) => itmInner.lsu_id === result.data[i].lsu_id + ), + }); + } + dispatch({ type: "FETCH_WORK_LOG_SUCCESS", payload: final }); + } catch (error) { + console.log(error); + } + }; + if (selectedTicket != null) { + fetchWorkLog(selectedTicket); + } + }, [workRefresh, selectedTicket]); + + useEffect(() => { + const fetchAssignLog = async (selectedTicket) => { + try { + const result = await axios.get( + "/assign/ticket/" + selectedTicket.ticket_id + ); + + const userResult = await axios.get("/user/admin"); + const final = userResult.data.filter((o) => + result.data.find(({ lsu_id }) => o.lsu_id === lsu_id) + ); + + dispatch({ type: "FETCH_ASSIGN_LOG_SUCCESS", payload: final }); + } catch (error) { + console.log(error); + } + }; + if (selectedTicket != null) { + fetchAssignLog(selectedTicket); + } + }, [assignmentRefresh, selectedTicket]); + + useEffect(() => { + const fetchData = async (selectedTicket) => { + String.prototype.toProperCase = function () { + return this.replace(/\w\S*/g, function (txt) { + return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); + }); + }; + + try { + dispatch({ type: "CLEAR_FORM" }); + const result = await axios.get("/ticket/" + selectedTicket.ticket_id); + let final = []; + for (const [key, value] of Object.entries(result.data)) { + console.log(`${key}: ${value}`); + final.push({ + name: key, + value: value, + error: false, + error_type: "none", + label: key.replace("_", " ").toProperCase(), + }); + } + + const union = _.unionBy(final, fields, "name"); + dispatch({ + type: "FETCH_TICKET_SUCCESS", + payload: union, + }); + } catch (error) { + console.log(error); + } + }; + if (selectedTicket != null) { + fetchData(selectedTicket); + } + }, [dataRefresh, selectedTicket]); + + const internalFormSubmit = async (e, data) => { + const response = await handleFormSubmit(e, data, "/ticket"); + if (response.status === 201) { + dispatch({ type: "CLEAR_FORM" }); + } + }; return ( <>

Customer Information

- - + {state.isLoading ? null : ( + <> + + + + )} + handleFormSubmit(e, data)} + onClick={(e) => internalFormSubmit(e, state.data)} > Submit
- + ); }; -export const ManageTicket = (props) => { - const [isLoadingStat, setStatLoading] = useState(false); - const [selectedTicket, setSelectedTicket] = useState(false); +export const ManageTicket = ({ technician }, ...props) => { + const [selectedTicket, setSelectedTicket] = useState(null); + const [tickets, setTickets] = useState(null); + const [isTicketsLoading, setIsTicketsLoading] = useState(true); - const [data, setData] = useState(fields); + useEffect(() => { + const fetchData = async () => { + try { + const result = await axios.get("ticket"); + setTickets(result.data); + setIsTicketsLoading(false); + } catch (error) { + console.log(error); + } + }; + + fetchData(); + }, []); - // TODO: get request for open and closed tickets. /api/ticket - // useEffect(async () => { - // const result = await axios.get(); - // }); const handleTicketSelection = (e, id) => { setSelectedTicket(id); }; @@ -74,53 +217,70 @@ export const ManageTicket = (props) => { return ( <>
- - - - - - - - - - - - - - - - + {isTicketsLoading === true ? null : ( + + + + + + + + + + + + )}

All Tickets

- Temp Table until DB is setup - +

- {selectedTicket === false + {selectedTicket === null ? "Create New Ticket" - : "Edit ____'s Ticket"} + : "Edit " + selectedTicket.first_name + "'s Ticket"}

- + {selectedTicket == null ? ( + "Please select ticket." + ) : ( + + )} ); diff --git a/client/src/routes/admin/NewTechnicianFlyout.js b/client/src/routes/admin/NewTechnicianFlyout.js index e8b5199..5232360 100644 --- a/client/src/routes/admin/NewTechnicianFlyout.js +++ b/client/src/routes/admin/NewTechnicianFlyout.js @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useEffect, useReducer, useState } from "react"; import { EuiFlyout, @@ -16,16 +16,28 @@ import { NewTechnicianForm } from "../../components/form/ManageTechnicianForm/Ne import { personFields } from "../../components/form/person/fields"; import { handleFormSubmit } from "../../components/form/ManageTicketForm/handlers"; import { Debug } from "../../components/debug/debug"; +import { dataFetchReducer } from "../../api/reducers"; export const NewTechnicianFlyout = ( { isFlyoutVisible, setIsFlyoutVisible }, ...props ) => { const closeFlyout = () => setIsFlyoutVisible(false); - const [data, setData] = useState(personFields); + + const [state, dispatch] = useReducer(dataFetchReducer, { + isLoading: false, + isError: false, + data: personFields, + }); const showFlyout = () => setIsFlyoutVisible(true); + const internalFormSubmit = (e, data) => { + if (handleFormSubmit(e, data, "/user") != null) { + setIsFlyoutVisible(false); + } + }; + if (isFlyoutVisible) { return ( - - -

New Technician

-
-
- - - - - - handleFormSubmit(e, data)} - > - Save - - - - - + {state.isLoading ? null : ( + <> + + +

New Technician

+
+
+ + + + + + { + internalFormSubmit(e, state.data); + }} + > + Save + + + + + + + )}
); } else { diff --git a/client/src/routes/admin/SelectTechnician.js b/client/src/routes/admin/SelectTechnician.js index 42f0d54..cef0910 100644 --- a/client/src/routes/admin/SelectTechnician.js +++ b/client/src/routes/admin/SelectTechnician.js @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useEffect, useReducer, useState } from "react"; import { EuiButton, @@ -15,6 +15,7 @@ import { } from "@elastic/eui"; import { MySelectField } from "../../components/form/MySelectField"; import { + handleDateChange, handleFormFieldBlur, handleFormFieldChange, } from "../../components/form/ManageTicketForm/handlers"; @@ -22,69 +23,115 @@ import { NewTechnicianFlyout } from "./NewTechnicianFlyout"; import { Debug } from "../../components/debug/debug"; import { fields, - selectOptions, + selectTechnicianOptions_default, } from "../../components/form/ManageTechnicianForm/fields"; +import axios from "../../api/api.js"; +import { dataFetchReducer } from "../../api/reducers"; +import { addToast } from "../../components/toast"; var _ = require("lodash"); -export const SelectTechnician = ({ setTechnician }, ...props) => { - const [data, setData] = useState(fields); +export const SelectTechnician = ({ technician, setTechnician }, ...props) => { const [isFlyoutVisible, setIsFlyoutVisible] = useState(false); + const [state, dispatch] = useReducer(dataFetchReducer, { + isLoading: false, + isError: false, + data: fields, + selectTechnicianOptions: selectTechnicianOptions_default, + }); + + useEffect(() => { + const fetchData = async () => { + try { + const result = await axios.get("/user/admin"); + const final = { + name: "technician", + options: result.data.map((o) => ({ + ...o, + value: o.lsu_id, + text: o.first_name + " " + o.last_name, + })), + }; + dispatch({ type: "FETCH_TECHNICIANS_SUCCESS", payload: final }); + } catch (error) { + dispatch({ type: "FETCH_FAILURE" }); + } + }; + + fetchData(); + }, []); + const handleFormSubmit = (e, data) => { + e.preventDefault(); const errors = _.find(data, ["error", true]); if (errors === undefined) { - console.log(data); - setTechnician(data); + if (data[0].value === "") { + addToast({ + title: "Select technician to continue", + color: "danger", + }); + } else { + console.log(data); + setTechnician(data); + } } }; return ( - - - - - -

Choose Technician

-
-
-
- - - handleFormFieldChange(e, data, setData)} - handleBlur={(e) => handleFormFieldBlur(e, data, setData)} - /> - - - - setIsFlyoutVisible(true)} - > - New - - - - handleFormSubmit(e, data)} - > - Select - - - - - - -
- -
+ <> + {state.isLoading ? null : ( + + + + + +

Choose Technician

+
+
+
+ + + { + handleFormFieldChange(e, state.data, dispatch); + }} + handleBlur={(e) => + handleFormFieldBlur(e, state.data, dispatch) + } + /> + + + + setIsFlyoutVisible(true)} + > + New + + + + handleFormSubmit(e, state.data)} + > + Select + + + + + + +
+ +
+ )} + ); }; diff --git a/client/src/routes/admin/Stats.js b/client/src/routes/admin/Stats.js new file mode 100644 index 0000000..53f4599 --- /dev/null +++ b/client/src/routes/admin/Stats.js @@ -0,0 +1,37 @@ +import { EuiIcon, EuiPanel, EuiStat } from "@elastic/eui"; +import React, { useEffect, useState, useReducer } from "react"; +import { dataFetchReducer } from "../../api/reducers"; +import axios from "../../api/api"; +import { ErrorCallout } from "../../components/callout/Callout"; + +export const MyStat = ( + { data, color, icon, description, filter, isLoading }, + ...props +) => { + const [items, setItems] = useState(null); + + useEffect(() => { + if (data != null) { + const i = data.filter((o) => o.status === filter).length; + setItems(i); + } + }, [data]); + + return ( + <> + + {isLoading ? null : ( + + + + )} + + + ); +}; diff --git a/client/src/routes/admin/admin.js b/client/src/routes/admin/admin.js index 8976cea..fc86871 100644 --- a/client/src/routes/admin/admin.js +++ b/client/src/routes/admin/admin.js @@ -21,12 +21,6 @@ import { EuiCode, } from "@elastic/eui"; import { NavBar } from "../../components/navbar/navbar"; -import { TicketsTable } from "../../components/table/openTickets"; -import { AdminTicketFlyout } from "../../components/flyout/flyout"; -import { UserView } from "../../components/form/ManageTicketForm/userView"; -import { fields } from "../../components/form/ManageTicketForm/fields"; -import { handleFormSubmit } from "../../components/form/ManageTicketForm/handlers"; -import { AdminView } from "../../components/form/ManageTicketForm/adminView"; import { SelectTechnician } from "./SelectTechnician"; import { ManageTicket } from "./ManageTicket"; @@ -43,9 +37,12 @@ export const AdminRoute = (props) => {
{technician === false ? ( - + ) : ( - + )}
diff --git a/client/src/routes/user/user.js b/client/src/routes/user/user.js index e030eff..4b42475 100644 --- a/client/src/routes/user/user.js +++ b/client/src/routes/user/user.js @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useEffect, useReducer, useState } from "react"; import { EuiPage, @@ -31,12 +31,25 @@ import { UserView } from "../../components/form/ManageTicketForm/userView"; import { fields } from "../../components/form/ManageTicketForm/fields"; import { handleFormSubmit } from "../../components/form/ManageTicketForm/handlers"; import { Debug } from "../../components/debug/debug"; +import { dataFetchReducer } from "../../api/reducers"; +import { selectTechnicianOptions_default } from "../../components/form/ManageTechnicianForm/fields"; var _ = require("lodash"); export const UserRoute = (props) => { - const [data, setData] = useState(fields); + const [state, dispatch] = useReducer(dataFetchReducer, { + isLoading: false, + isError: false, + data: fields, + }); + const internalFormSubmit = async (e, data) => { + data.find((o) => o.name === "component").value = "N/A"; + const response = await handleFormSubmit(e, data, "/ticket"); + if (response.status === 201) { + // dispatch({ type: "CLEAR_FORM" }); + } + }; return ( <> @@ -50,32 +63,25 @@ export const UserRoute = (props) => { - {/**/} - {/* */} - {/* */} - {/*

Submit Ticket

*/} - {/*
*/} - {/*
*/} - {/*
*/}

My Information

- + handleFormSubmit(e, data)} + onClick={(e) => internalFormSubmit(e, state.data)} > Submit - +