feat: Initialize monorepo structure and comprehensive documentation
This commit establishes the new monorepo architecture for the KROW Workforce platform. Key changes include: - Reorganized project into `frontend-web`, `mobile-apps`, `firebase`, `scripts`, and `secrets` directories. - Updated `Makefile` to support the new monorepo layout and automate Base44 export integration. - Fixed `scripts/prepare-export.js` for ES module compatibility and global component import resolution. - Created and updated `CONTRIBUTING.md` for developer onboarding. - Restructured, renamed, and translated all `docs/` files for clarity and consistency. - Implemented an interactive internal launchpad with diagram viewing capabilities. - Configured base Firebase project files (`firebase.json`, security rules). - Updated `README.md` to reflect the new project structure and documentation overview.
This commit is contained in:
196
frontend-web/src/pages/AddSector.jsx
Normal file
196
frontend-web/src/pages/AddSector.jsx
Normal file
@@ -0,0 +1,196 @@
|
||||
import React, { useState } from "react";
|
||||
import { base44 } from "@/api/base44Client";
|
||||
import { useMutation, useQueryClient, useQuery } from "@tanstack/react-query";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { createPageUrl } from "@/utils";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { MapPin, ArrowLeft, Check } from "lucide-react";
|
||||
import PageHeader from "../components/common/PageHeader";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
|
||||
export default function AddSector() {
|
||||
const navigate = useNavigate();
|
||||
const queryClient = useQueryClient();
|
||||
const { toast } = useToast();
|
||||
|
||||
const { data: enterprises = [] } = useQuery({
|
||||
queryKey: ['enterprises'],
|
||||
queryFn: () => base44.entities.Enterprise.list(),
|
||||
initialData: [],
|
||||
});
|
||||
|
||||
const generateSectorNumber = () => {
|
||||
const randomNum = Math.floor(1000 + Math.random() * 9000);
|
||||
return `SN-${randomNum}`;
|
||||
};
|
||||
|
||||
const [sectorData, setSectorData] = useState({
|
||||
sector_number: generateSectorNumber(),
|
||||
sector_name: "",
|
||||
sector_code: "",
|
||||
parent_enterprise_id: "",
|
||||
parent_enterprise_name: "",
|
||||
sector_type: "Food Service",
|
||||
sector_policies: {
|
||||
uniform_requirements: "",
|
||||
certification_requirements: [],
|
||||
special_training: []
|
||||
},
|
||||
is_active: true
|
||||
});
|
||||
|
||||
const createSectorMutation = useMutation({
|
||||
mutationFn: (data) => base44.entities.Sector.create(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['sectors'] });
|
||||
toast({
|
||||
title: "Sector Created",
|
||||
description: "Sector has been successfully added to the platform",
|
||||
});
|
||||
navigate(createPageUrl("SectorManagement"));
|
||||
},
|
||||
});
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
createSectorMutation.mutate(sectorData);
|
||||
};
|
||||
|
||||
const handleEnterpriseChange = (enterpriseId) => {
|
||||
const enterprise = enterprises.find(e => e.id === enterpriseId);
|
||||
setSectorData({
|
||||
...sectorData,
|
||||
parent_enterprise_id: enterpriseId,
|
||||
parent_enterprise_name: enterprise?.enterprise_name || ""
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="p-4 md:p-8 bg-slate-50 min-h-screen">
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<PageHeader
|
||||
title="Add Sector"
|
||||
subtitle="Add a new operating brand/sector to the platform"
|
||||
backTo={createPageUrl("SectorManagement")}
|
||||
backButtonLabel="Back to Sectors"
|
||||
/>
|
||||
|
||||
<form onSubmit={handleSubmit}>
|
||||
<Card className="mb-6 border-slate-200 shadow-lg">
|
||||
<CardHeader className="bg-gradient-to-br from-slate-50 to-white border-b">
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<MapPin className="w-5 h-5 text-[#0A39DF]" />
|
||||
Basic Information
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="p-6 space-y-6">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<Label htmlFor="sector_number">Sector Number</Label>
|
||||
<Input
|
||||
id="sector_number"
|
||||
value={sectorData.sector_number}
|
||||
readOnly
|
||||
className="bg-slate-50 font-mono"
|
||||
/>
|
||||
<p className="text-xs text-slate-500 mt-1">Auto-generated unique ID</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label htmlFor="sector_code">Sector Code *</Label>
|
||||
<Input
|
||||
id="sector_code"
|
||||
placeholder="e.g., BON"
|
||||
value={sectorData.sector_code}
|
||||
onChange={(e) => setSectorData({...sectorData, sector_code: e.target.value.toUpperCase()})}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="md:col-span-2">
|
||||
<Label htmlFor="sector_name">Sector Name *</Label>
|
||||
<Input
|
||||
id="sector_name"
|
||||
placeholder="e.g., Bon Appétit"
|
||||
value={sectorData.sector_name}
|
||||
onChange={(e) => setSectorData({...sectorData, sector_name: e.target.value})}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label htmlFor="parent_enterprise">Parent Enterprise</Label>
|
||||
<Select onValueChange={handleEnterpriseChange} value={sectorData.parent_enterprise_id}>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select enterprise" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{enterprises.map((enterprise) => (
|
||||
<SelectItem key={enterprise.id} value={enterprise.id}>
|
||||
{enterprise.enterprise_name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label htmlFor="sector_type">Sector Type *</Label>
|
||||
<Select onValueChange={(value) => setSectorData({...sectorData, sector_type: value})} value={sectorData.sector_type}>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="Food Service">Food Service</SelectItem>
|
||||
<SelectItem value="Facilities">Facilities</SelectItem>
|
||||
<SelectItem value="Healthcare">Healthcare</SelectItem>
|
||||
<SelectItem value="Education">Education</SelectItem>
|
||||
<SelectItem value="Corporate">Corporate</SelectItem>
|
||||
<SelectItem value="Sports & Entertainment">Sports & Entertainment</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label htmlFor="uniform_requirements">Uniform Requirements</Label>
|
||||
<Input
|
||||
id="uniform_requirements"
|
||||
placeholder="e.g., Black chef coat, black pants, non-slip shoes"
|
||||
value={sectorData.sector_policies.uniform_requirements}
|
||||
onChange={(e) => setSectorData({
|
||||
...sectorData,
|
||||
sector_policies: {...sectorData.sector_policies, uniform_requirements: e.target.value}
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<div className="flex justify-end gap-3">
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
onClick={() => navigate(createPageUrl("SectorManagement"))}
|
||||
>
|
||||
<ArrowLeft className="w-4 h-4 mr-2" />
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
type="submit"
|
||||
className="bg-[#0A39DF] hover:bg-[#0A39DF]/90"
|
||||
disabled={createSectorMutation.isPending}
|
||||
>
|
||||
<Check className="w-4 h-4 mr-2" />
|
||||
{createSectorMutation.isPending ? "Creating..." : "Create Sector"}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user