initial scaffolding
This commit is contained in:
@ -0,0 +1,20 @@
|
||||
import React, { useState } from "react";
|
||||
import TicketForm from "./TicketForm";
|
||||
|
||||
const CreateTicket: React.FC = () => {
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
return (
|
||||
<div className="ticket-container">
|
||||
<div className="ticket-header">
|
||||
<h2>Create New Ticket</h2>
|
||||
</div>
|
||||
|
||||
{error && <div className="error-message">{error}</div>}
|
||||
|
||||
<TicketForm onError={setError} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CreateTicket;
|
||||
@ -0,0 +1,73 @@
|
||||
import React, { useState } from "react";
|
||||
import TicketFieldRow from "./TicketRow";
|
||||
import TicketTextarea from "./TicketText";
|
||||
import type { TicketFormData } from "../../types/ticket";
|
||||
|
||||
interface TicketFormProps {
|
||||
onError: (msg: string | null) => void;
|
||||
}
|
||||
|
||||
const TicketForm: React.FC<TicketFormProps> = ({ onError }) => {
|
||||
const [form, setForm] = useState<TicketFormData>({
|
||||
title: "",
|
||||
status: "Open",
|
||||
priority: "4",
|
||||
category: "General",
|
||||
type: "Issue",
|
||||
description: "",
|
||||
});
|
||||
|
||||
function updateField(field: keyof TicketFormData, value: string) {
|
||||
setForm(prev => ({ ...prev, [field]: value }));
|
||||
}
|
||||
|
||||
function handleSubmit(e: React.FormEvent) {
|
||||
e.preventDefault();
|
||||
|
||||
if (!form.title.trim() || !form.description.trim()) {
|
||||
onError("Title and description are required.");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Submitting:", form);
|
||||
// Later: POST to Express/PHP
|
||||
}
|
||||
|
||||
return (
|
||||
<form className="ticket-form" onSubmit={handleSubmit}>
|
||||
<div className="ticket-details">
|
||||
<div className="detail-group">
|
||||
<label>Title</label>
|
||||
<input
|
||||
type="text"
|
||||
value={form.title}
|
||||
onChange={e => updateField("title", e.target.value)}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<TicketFieldRow form={form} updateField={updateField} />
|
||||
|
||||
<TicketTextarea
|
||||
label="Description"
|
||||
value={form.description}
|
||||
onChange={value => updateField("description", value)}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="ticket-footer">
|
||||
<button type="submit" className="btn primary">Create Ticket</button>
|
||||
<button
|
||||
type="button"
|
||||
className="btn back-btn"
|
||||
onClick={() => (window.location.href = "/")}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
export default TicketForm;
|
||||
@ -0,0 +1,68 @@
|
||||
import React from "react";
|
||||
import TicketSelect from "./TicketSelect";
|
||||
import type { TicketFormData } from "../../types/ticket";
|
||||
|
||||
interface TicketRowProps {
|
||||
form: TicketFormData;
|
||||
updateField: (field: keyof TicketFormData, value: string) => void;
|
||||
}
|
||||
|
||||
const TicketRow: React.FC<TicketRowProps> = ({ form, updateField }) => {
|
||||
return (
|
||||
<div className="detail-group status-priority-row">
|
||||
<TicketSelect
|
||||
label="Status"
|
||||
field="status"
|
||||
value={form.status}
|
||||
updateField={updateField}
|
||||
options={[
|
||||
{ value: "Open", label: "Open" },
|
||||
{ value: "Closed", label: "Closed" },
|
||||
]}
|
||||
/>
|
||||
|
||||
<TicketSelect
|
||||
label="Priority"
|
||||
field="priority"
|
||||
value={form.priority}
|
||||
updateField={updateField}
|
||||
options={[
|
||||
{ value: "1", label: "P1 - Critical Impact" },
|
||||
{ value: "2", label: "P2 - High Impact" },
|
||||
{ value: "3", label: "P3 - Medium Impact" },
|
||||
{ value: "4", label: "P4 - Low Impact" },
|
||||
]}
|
||||
/>
|
||||
|
||||
<TicketSelect
|
||||
label="Category"
|
||||
field="category"
|
||||
value={form.category}
|
||||
updateField={updateField}
|
||||
options={[
|
||||
{ value: "Hardware", label: "Hardware" },
|
||||
{ value: "Software", label: "Software" },
|
||||
{ value: "Network", label: "Network" },
|
||||
{ value: "Security", label: "Security" },
|
||||
{ value: "General", label: "General" },
|
||||
]}
|
||||
/>
|
||||
|
||||
<TicketSelect
|
||||
label="Type"
|
||||
field="type"
|
||||
value={form.type}
|
||||
updateField={updateField}
|
||||
options={[
|
||||
{ value: "Maintenance", label: "Maintenance" },
|
||||
{ value: "Install", label: "Install" },
|
||||
{ value: "Task", label: "Task" },
|
||||
{ value: "Upgrade", label: "Upgrade" },
|
||||
{ value: "Issue", label: "Issue" },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TicketRow;
|
||||
@ -0,0 +1,37 @@
|
||||
import React from "react";
|
||||
import type { SelectOption, TicketFormData } from "../../types/ticket";
|
||||
|
||||
interface TicketSelectProps {
|
||||
label: string;
|
||||
field: keyof TicketFormData;
|
||||
value: string;
|
||||
options: SelectOption[];
|
||||
updateField: (field: keyof TicketFormData, value: string) => void;
|
||||
}
|
||||
|
||||
const TicketSelect: React.FC<TicketSelectProps> = ({
|
||||
label,
|
||||
field,
|
||||
value,
|
||||
options,
|
||||
updateField,
|
||||
}) => {
|
||||
return (
|
||||
<div className="detail-quarter">
|
||||
<label>{label}</label>
|
||||
|
||||
<select
|
||||
value={value}
|
||||
onChange={e => updateField(field, e.target.value)}
|
||||
>
|
||||
{options.map(opt => (
|
||||
<option key={opt.value} value={opt.value}>
|
||||
{opt.label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TicketSelect;
|
||||
@ -0,0 +1,30 @@
|
||||
import React from "react";
|
||||
|
||||
interface TicketTextProps {
|
||||
label: string;
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
required?: boolean;
|
||||
}
|
||||
|
||||
const TicketText: React.FC<TicketTextProps> = ({
|
||||
label,
|
||||
value,
|
||||
onChange,
|
||||
required,
|
||||
}) => {
|
||||
return (
|
||||
<div className="detail-group full-width">
|
||||
<label>{label}</label>
|
||||
|
||||
<textarea
|
||||
rows={15}
|
||||
value={value}
|
||||
required={required}
|
||||
onChange={e => onChange(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TicketText;
|
||||
Reference in New Issue
Block a user