update ui design for all pages

This commit is contained in:
2026-08-12 18:56:56 +05:30
parent 25c4ee4a6a
commit 3beb66059b
58 changed files with 7892 additions and 1891 deletions

View File

@@ -1,47 +1,36 @@
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useLocation, useNavigate } from 'react-router-dom';
import { Sparkles, ChevronDown, ChevronUp, Sliders, Loader2, Star } from 'lucide-react';
import { useCreateJobPosting, useUpdateJobPosting, useGenerateJobDescription, useRoleCategories, useCreateRoleCategory } from '@/lib/krowHooks';
import { toast } from 'react-hot-toast';
import { ROLE_CATEGORIES } from '@/lib/roleCategories';
import { CERT_OPTIONS, CRITERIA_LABELS, ENGLISH_LEVELS, defaultPosition } from '@/lib/positionModel';
const ROLE_CATEGORIES = ['Server', 'Bartender', 'Chef', 'Security', 'Picker', 'Event Staff', 'Other'];
const CERT_OPTIONS = ['Food Handler Card', 'ServSafe', 'ABC License', 'TIPS Certified', 'CPR/First Aid', 'Background Check Cleared'];
const ENGLISH_LEVELS = [
{ value: 'basic', label: 'Basic' },
{ value: 'conversational', label: 'Conversational' },
{ value: 'fluent', label: 'Fluent' },
{ value: 'native', label: 'Native' },
];
const CRITERIA_LABELS = {
experience: 'Experience',
english: 'English',
reliability: 'Reliability',
certifications: 'Certifications',
availability: 'Availability',
};
export default function CreatePosition() {
/**
* Create a Position.
*
* The manual form, reachable at `/admin/positions/new`. `embedded` drops the
* page header for a host that supplies its own, and `onDone` lets that host
* close it instead of navigating away.
*
* Owliver does not open this form. Asking Owliver for a position is a
* conversation that ends in the same record (see `lib/skills/positionFlow.js`),
* and both paths share one field definition — `lib/positionModel.js` — so
* neither can drift into a different shape of position.
*/
export default function CreatePosition({ prefill: prefillProp, embedded = false, onDone }) {
const navigate = useNavigate();
/* Owliver opens this page with the fields it could infer from the request.
It is a starting point, not a submission: every field stays editable and
the position is still created by the button at the bottom. */
const { state } = useLocation();
const prefill = prefillProp || state?.prefill || null;
const createJob = useCreateJobPosting();
const updateJob = useUpdateJobPosting();
const generateDesc = useGenerateJobDescription();
const [form, setForm] = useState({
title: '',
role_category: 'Server',
custom_requirements: '',
physical_requirements: '',
leadership_expectations: '',
attendance_expectations: '',
min_experience_years: 0,
english_required: 'basic',
location: '',
pay_range_min: '',
pay_range_max: '',
certifications_required: [],
vetting_criteria: { experience: 25, english: 20, reliability: 20, certifications: 20, availability: 15 },
});
const [form, setForm] = useState({ ...defaultPosition(), ...prefill });
const { data: customCategories = [] } = useRoleCategories();
const createRoleCategory = useCreateRoleCategory();
const [newCategory, setNewCategory] = useState('');
@@ -111,10 +100,14 @@ export default function CreatePosition() {
createdId = created?.id;
}
toast.success(status === 'active' ? 'Job posting published!' : 'Saved as draft');
if (status === 'active' && createdId) {
navigate(`/positions/${createdId}`);
/* Inline, the list behind the form is already the destination — closing
returns to it with the new position in place. */
if (onDone) {
onDone(createdId);
} else if (status === 'active' && createdId) {
navigate(`/admin/positions/${createdId}`);
} else {
navigate('/positions');
navigate('/admin/positions');
}
} catch (e) {
toast.error('Failed to save');
@@ -122,18 +115,22 @@ export default function CreatePosition() {
};
return (
<div className="max-w-3xl mx-auto">
<div className={embedded ? '' : 'max-w-3xl mx-auto'}>
{/* Header */}
<div className="flex items-center justify-between mb-6">
<div>
<h1 className="text-[22px] font-bold text-[#111827]">Create a Position</h1>
<p className="text-[13px] text-[#6B7280] mt-0.5">Set hiring criteria once — KROW interviews and ranks every applicant automatically.</p>
{!embedded && (
<div className="flex items-center justify-between mb-6">
<div>
<h1 className="text-[22px] font-bold text-[#111827]">Create a Position</h1>
<p className="text-[13px] text-[#6B7280] mt-0.5">Set hiring criteria once — KROW interviews and ranks every applicant automatically.</p>
</div>
<button onClick={() => navigate('/admin/positions')} className="text-[13px] text-[#6B7280] hover:text-[#111827]">Cancel</button>
</div>
<button onClick={() => navigate('/positions')} className="text-[13px] text-[#6B7280] hover:text-[#111827]">Cancel</button>
</div>
)}
{/* Card */}
<div className="bg-white border border-[#E5E7EB] rounded-2xl p-6 md:p-8 space-y-6">
<div className={embedded
? 'space-y-6'
: 'bg-white border border-[#E5E7EB] rounded-2xl p-6 md:p-8 space-y-6'}>
{/* Section Header */}
<div className="flex items-center gap-2">
<div className="w-7 h-7 rounded-lg bg-[#EFF6FF] flex items-center justify-center">