Docker-Images bauen und veröffentlichen / build (, omsorgCore/Dockerfile, omsorgcore) (push) Successful in 3s
Docker-Images bauen und veröffentlichen / build (, omsorgWeb/Dockerfile, omsorgweb) (push) Failing after 4s
Docker-Images bauen und veröffentlichen / build (VITE_OMSORG_CORE_URL=${{ vars.OMSORG_CORE_PUBLIC_URL }}, omsorgapp/Dockerfile, omsorgapp) (push) Successful in 3s
- omsorgapp: drop Electron, run as a plain Vite/React browser app; refresh token moves to an HttpOnly cookie (omsorgCore), CORS added for the new browser origin, document download/preview switched to Blob-based browser APIs. - Add Dockerfiles for omsorgCore, omsorgapp, and omsorgWeb, a docker-compose.yml wiring Postgres/MySQL/all three apps together, and a Gitea Actions workflow that builds and pushes images to the repo's container registry on push to main and on version tags. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
216 lines
6.9 KiB
React
216 lines
6.9 KiB
React
import OmsorgButton from "../../components/ui/OmsorgButton";
|
|
import { useValueListItems } from "../../app/useValueListItems";
|
|
|
|
export const emptyEmployeeForm = {
|
|
firstName: "",
|
|
lastName: "",
|
|
status: "Aktiv",
|
|
dateOfBirth: "",
|
|
street: "",
|
|
postalCode: "",
|
|
city: "",
|
|
country: "",
|
|
phoneNumber: "",
|
|
email: "",
|
|
entryDate: "",
|
|
exitDate: "",
|
|
emergencyContactName: "",
|
|
emergencyContactPhone: "",
|
|
emergencyContactRelation: "",
|
|
employmentType: "",
|
|
qualification: "",
|
|
};
|
|
|
|
export function employeeToFormValues(employee) {
|
|
return {
|
|
firstName: employee.firstName ?? "",
|
|
lastName: employee.lastName ?? "",
|
|
status: employee.status ?? "Aktiv",
|
|
dateOfBirth: employee.dateOfBirth ?? "",
|
|
street: employee.street ?? "",
|
|
postalCode: employee.postalCode ?? "",
|
|
city: employee.city ?? "",
|
|
country: employee.country ?? "",
|
|
phoneNumber: employee.phoneNumber ?? "",
|
|
email: employee.email ?? "",
|
|
entryDate: employee.entryDate ?? "",
|
|
exitDate: employee.exitDate ?? "",
|
|
emergencyContactName: employee.emergencyContactName ?? "",
|
|
emergencyContactPhone: employee.emergencyContactPhone ?? "",
|
|
emergencyContactRelation: employee.emergencyContactRelation ?? "",
|
|
employmentType: employee.employmentType ?? "",
|
|
qualification: employee.qualification ?? "",
|
|
};
|
|
}
|
|
|
|
export function employeeFormToPayload(form, { includeStatus = false } = {}) {
|
|
const payload = {
|
|
firstName: form.firstName.trim(),
|
|
lastName: form.lastName.trim(),
|
|
dateOfBirth: form.dateOfBirth || null,
|
|
street: form.street.trim() || null,
|
|
postalCode: form.postalCode.trim() || null,
|
|
city: form.city.trim() || null,
|
|
country: form.country.trim() || null,
|
|
phoneNumber: form.phoneNumber.trim() || null,
|
|
email: form.email.trim() || null,
|
|
entryDate: form.entryDate || null,
|
|
exitDate: form.exitDate || null,
|
|
emergencyContactName: form.emergencyContactName.trim() || null,
|
|
emergencyContactPhone: form.emergencyContactPhone.trim() || null,
|
|
emergencyContactRelation: form.emergencyContactRelation.trim() || null,
|
|
employmentType: form.employmentType || null,
|
|
qualification: form.qualification.trim() || null,
|
|
};
|
|
|
|
if (includeStatus) {
|
|
payload.status = form.status;
|
|
}
|
|
|
|
return payload;
|
|
}
|
|
|
|
export default function EmployeeForm({ form, onChange, includeStatus = false }) {
|
|
const { items: statusOptions } = useValueListItems("EmployeeStatus");
|
|
const { items: employmentTypes } = useValueListItems("EmploymentType");
|
|
const { items: qualifications } = useValueListItems("Qualification");
|
|
|
|
function updateField(field) {
|
|
return (event) => onChange({ ...form, [field]: event.target.value });
|
|
}
|
|
|
|
return (
|
|
<div className="form-grid">
|
|
<label className="form-field">
|
|
<span>Vorname *</span>
|
|
<input value={form.firstName} onChange={updateField("firstName")} required />
|
|
</label>
|
|
|
|
<label className="form-field">
|
|
<span>Nachname *</span>
|
|
<input value={form.lastName} onChange={updateField("lastName")} required />
|
|
</label>
|
|
|
|
{includeStatus && (
|
|
<label className="form-field">
|
|
<span>Status</span>
|
|
<select value={form.status} onChange={updateField("status")}>
|
|
{statusOptions.map((option) => (
|
|
<option key={option.id} value={option.value}>
|
|
{option.value}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</label>
|
|
)}
|
|
|
|
<label className="form-field">
|
|
<span>Geburtsdatum</span>
|
|
<input type="date" value={form.dateOfBirth} onChange={updateField("dateOfBirth")} />
|
|
</label>
|
|
|
|
<fieldset className="form-field form-field--fieldset">
|
|
<legend>Adresse</legend>
|
|
|
|
<label className="form-field">
|
|
<span>Straße und Hausnummer</span>
|
|
<input value={form.street} onChange={updateField("street")} />
|
|
</label>
|
|
|
|
<div className="form-row">
|
|
<label className="form-field">
|
|
<span>PLZ</span>
|
|
<input value={form.postalCode} onChange={updateField("postalCode")} />
|
|
</label>
|
|
|
|
<label className="form-field">
|
|
<span>Ort</span>
|
|
<input value={form.city} onChange={updateField("city")} />
|
|
</label>
|
|
</div>
|
|
|
|
<label className="form-field">
|
|
<span>Land</span>
|
|
<input value={form.country} onChange={updateField("country")} />
|
|
</label>
|
|
</fieldset>
|
|
|
|
<label className="form-field">
|
|
<span>Telefon</span>
|
|
<input value={form.phoneNumber} onChange={updateField("phoneNumber")} />
|
|
</label>
|
|
|
|
<label className="form-field">
|
|
<span>E-Mail</span>
|
|
<input type="email" value={form.email} onChange={updateField("email")} />
|
|
</label>
|
|
|
|
<label className="form-field">
|
|
<span>Eintrittsdatum</span>
|
|
<input type="date" value={form.entryDate} onChange={updateField("entryDate")} />
|
|
</label>
|
|
|
|
<label className="form-field">
|
|
<span>Austrittsdatum</span>
|
|
<input type="date" value={form.exitDate} onChange={updateField("exitDate")} />
|
|
</label>
|
|
|
|
<label className="form-field">
|
|
<span>Beschäftigungsart</span>
|
|
<select value={form.employmentType} onChange={updateField("employmentType")}>
|
|
<option value="">— nicht angegeben —</option>
|
|
{employmentTypes.map((option) => (
|
|
<option key={option.id} value={option.value}>
|
|
{option.value}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</label>
|
|
|
|
<label className="form-field">
|
|
<span>Qualifikation</span>
|
|
<select value={form.qualification} onChange={updateField("qualification")}>
|
|
<option value="">— nicht angegeben —</option>
|
|
{qualifications.map((option) => (
|
|
<option key={option.id} value={option.value}>
|
|
{option.value}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</label>
|
|
|
|
<fieldset className="form-field form-field--fieldset">
|
|
<legend>Notfallkontakt</legend>
|
|
|
|
<label className="form-field">
|
|
<span>Name</span>
|
|
<input value={form.emergencyContactName} onChange={updateField("emergencyContactName")} />
|
|
</label>
|
|
|
|
<label className="form-field">
|
|
<span>Telefon</span>
|
|
<input value={form.emergencyContactPhone} onChange={updateField("emergencyContactPhone")} />
|
|
</label>
|
|
|
|
<label className="form-field">
|
|
<span>Beziehung</span>
|
|
<input value={form.emergencyContactRelation} onChange={updateField("emergencyContactRelation")} />
|
|
</label>
|
|
</fieldset>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function FormActions({ onCancel, isSaving, submitLabel }) {
|
|
return (
|
|
<div className="form-actions">
|
|
<OmsorgButton variant="secondary" type="button" onClick={onCancel} disabled={isSaving}>
|
|
Abbrechen
|
|
</OmsorgButton>
|
|
<OmsorgButton type="submit" disabled={isSaving}>
|
|
{isSaving ? "Speichert..." : submitLabel}
|
|
</OmsorgButton>
|
|
</div>
|
|
);
|
|
}
|