Compare commits
4 Commits
1.1
..
e05a7382c1
| Author | SHA1 | Date | |
|---|---|---|---|
| e05a7382c1 | |||
| a635c57d5d | |||
| 508c96eedd | |||
| ffee4b6e7d |
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"pages": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"polyfillFiles": [
|
||||||
|
"static/chunks/polyfills.js"
|
||||||
|
],
|
||||||
|
"devFiles": [],
|
||||||
|
"ampDevFiles": [],
|
||||||
|
"lowPriorityFiles": [
|
||||||
|
"static/development/_buildManifest.js",
|
||||||
|
"static/development/_ssgManifest.js"
|
||||||
|
],
|
||||||
|
"rootMainFiles": [],
|
||||||
|
"pages": {
|
||||||
|
"/_app": []
|
||||||
|
},
|
||||||
|
"ampFirstPages": []
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
{"type": "commonjs"}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
self.__INTERCEPTION_ROUTE_REWRITE_MANIFEST="[]"
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
self.__BUILD_MANIFEST = {
|
||||||
|
"polyfillFiles": [
|
||||||
|
"static/chunks/polyfills.js"
|
||||||
|
],
|
||||||
|
"devFiles": [],
|
||||||
|
"ampDevFiles": [],
|
||||||
|
"lowPriorityFiles": [],
|
||||||
|
"rootMainFiles": [],
|
||||||
|
"pages": {
|
||||||
|
"/_app": []
|
||||||
|
},
|
||||||
|
"ampFirstPages": []
|
||||||
|
};
|
||||||
|
self.__BUILD_MANIFEST.lowPriorityFiles = [
|
||||||
|
"/static/" + process.env.__NEXT_BUILD_ID + "/_buildManifest.js",
|
||||||
|
,"/static/" + process.env.__NEXT_BUILD_ID + "/_ssgManifest.js",
|
||||||
|
|
||||||
|
];
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"middleware": {},
|
||||||
|
"functions": {},
|
||||||
|
"sortedMiddleware": []
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
self.__REACT_LOADABLE_MANIFEST="{}"
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
self.__NEXT_FONT_MANIFEST="{\"pages\":{},\"app\":{},\"appUsingSizeAdjust\":false,\"pagesUsingSizeAdjust\":false}"
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"pages":{},"app":{},"appUsingSizeAdjust":false,"pagesUsingSizeAdjust":false}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
self.__RSC_SERVER_MANIFEST="{\n \"node\": {},\n \"edge\": {},\n \"encryptionKey\": \"process.env.NEXT_SERVER_ACTIONS_ENCRYPTION_KEY\"\n}"
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"node": {},
|
||||||
|
"edge": {},
|
||||||
|
"encryptionKey": "4wbouw6RrCkiRBuhNA0RdY1ZJ0IOxBnrfMXrawt4S9g="
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
|||||||
|
self.__BUILD_MANIFEST = {__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},sortedPages:["\u002F_app"]};self.__BUILD_MANIFEST_CB && self.__BUILD_MANIFEST_CB()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
self.__SSG_MANIFEST=new Set;self.__SSG_MANIFEST_CB&&self.__SSG_MANIFEST_CB()
|
||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
|||||||
|
{"type": "module"}
|
||||||
+27
-108
@@ -83,7 +83,6 @@ interface Stats {
|
|||||||
interface UserData {
|
interface UserData {
|
||||||
national_id: string
|
national_id: string
|
||||||
name: string
|
name: string
|
||||||
role?: string
|
|
||||||
in_shelter?: string
|
in_shelter?: string
|
||||||
last_updated?: string
|
last_updated?: string
|
||||||
is_admin: boolean
|
is_admin: boolean
|
||||||
@@ -651,64 +650,35 @@ export default function AdminPage() {
|
|||||||
const handleAddUser = async (e: React.FormEvent) => {
|
const handleAddUser = async (e: React.FormEvent) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
const trimmedField = newUser.field.trim()
|
if (!newUser.field || !newUser.department || !newUser.team || !newUser.role) {
|
||||||
const trimmedDepartment = newUser.department.trim()
|
setMessage("יש לבחור תפקיד, תחום, מסגרת וצוות")
|
||||||
const trimmedTeam = newUser.team.trim()
|
|
||||||
const selectedRole = newUser.role as UserRole
|
|
||||||
|
|
||||||
if (!trimmedField || !selectedRole) {
|
|
||||||
setMessage("Please fill in the required fields.")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedRole === "department_admin") {
|
|
||||||
if (!trimmedDepartment) {
|
|
||||||
setMessage("Please fill in the required fields.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else if (selectedRole === "team_admin" || selectedRole === "user") {
|
|
||||||
if (!trimmedDepartment || !trimmedTeam) {
|
|
||||||
setMessage("Please fill in the required fields.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const payload = {
|
|
||||||
...newUser,
|
|
||||||
field: trimmedField,
|
|
||||||
department: trimmedDepartment,
|
|
||||||
team: trimmedTeam,
|
|
||||||
adminId: user?.national_id,
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedRole === "field_admin") {
|
|
||||||
payload.department = ""
|
|
||||||
payload.team = ""
|
|
||||||
} else if (selectedRole === "department_admin") {
|
|
||||||
payload.team = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await fetch("/api/admin/add-user", {
|
const response = await fetch("/api/admin/add-user", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify(payload),
|
body: JSON.stringify({
|
||||||
|
...newUser,
|
||||||
|
adminId: user?.national_id,
|
||||||
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
const data = await response.json()
|
const data = await response.json()
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
setMessage(`${data.message}. Default password: password123`)
|
setMessage(`${data.message}. הסיסמה הזמנית: password123`)
|
||||||
setNewUser({ name: "", isAdmin: false, field: "", department: "", team: "", role: "" })
|
setNewUser({ name: "", isAdmin: false, field: "", department: "", team: "", role: "" })
|
||||||
refetchGlobal()
|
refetchGlobal()
|
||||||
refetchTeam()
|
refetchTeam()
|
||||||
refetchDepartment()
|
refetchDepartment()
|
||||||
refetchField()
|
refetchField()
|
||||||
} else {
|
} else {
|
||||||
setMessage(data.error || "Failed to add user.")
|
setMessage(data.error || "שגיאה בהוספת משתמש")
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setMessage("Failed to add user.")
|
setMessage("שגיאה בחיבור לשרת")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1160,34 +1130,6 @@ export default function AdminPage() {
|
|||||||
}
|
}
|
||||||
}, [allowedManagedTabs, managedTypeTab])
|
}, [allowedManagedTabs, managedTypeTab])
|
||||||
|
|
||||||
const canShowTeamTab =
|
|
||||||
(user?.role === "team_admin" && !!user?.team) || (user?.role === "global_admin" && !!user?.team)
|
|
||||||
const canShowDepartmentTab =
|
|
||||||
(user?.role === "department_admin" && !!user?.department) ||
|
|
||||||
(user?.role === "global_admin" && !!user?.department)
|
|
||||||
const canShowFieldTab =
|
|
||||||
user?.role === "field_admin" || (user?.role === "global_admin" && !!user?.field)
|
|
||||||
const visibleTabs = [
|
|
||||||
canShowTeamTab ? "team" : null,
|
|
||||||
canShowDepartmentTab ? "department" : null,
|
|
||||||
canShowFieldTab ? "field" : null,
|
|
||||||
"global",
|
|
||||||
].filter(Boolean) as string[]
|
|
||||||
const tabColumns =
|
|
||||||
visibleTabs.length === 1
|
|
||||||
? "grid-cols-1"
|
|
||||||
: visibleTabs.length === 2
|
|
||||||
? "grid-cols-2"
|
|
||||||
: visibleTabs.length === 3
|
|
||||||
? "grid-cols-3"
|
|
||||||
: "grid-cols-4"
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (visibleTabs.length > 0 && !visibleTabs.includes(activeTab)) {
|
|
||||||
setActiveTab(visibleTabs[0])
|
|
||||||
}
|
|
||||||
}, [activeTab, visibleTabs])
|
|
||||||
|
|
||||||
if (!user) return null
|
if (!user) return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -1262,32 +1204,25 @@ export default function AdminPage() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<Tabs value={activeTab} onValueChange={setActiveTab} className="w-full" dir="rtl">
|
<Tabs value={activeTab} onValueChange={setActiveTab} className="w-full" dir="rtl">
|
||||||
<TabsList className={`grid w-full ${tabColumns}`}>
|
<TabsList className="grid w-full grid-cols-4">
|
||||||
{canShowTeamTab && (
|
<TabsTrigger value="team" className="flex items-center gap-2">
|
||||||
<TabsTrigger value="team" className="flex items-center gap-2">
|
<UsersIcon className="h-4 w-4" />
|
||||||
<UsersIcon className="h-4 w-4" />
|
צוות
|
||||||
צוות
|
</TabsTrigger>
|
||||||
</TabsTrigger>
|
<TabsTrigger value="department" className="flex items-center gap-2">
|
||||||
)}
|
<Building2 className="h-4 w-4" />
|
||||||
{canShowDepartmentTab && (
|
מסגרת
|
||||||
<TabsTrigger value="department" className="flex items-center gap-2">
|
</TabsTrigger>
|
||||||
<Building2 className="h-4 w-4" />
|
<TabsTrigger value="field" className="flex items-center gap-2">
|
||||||
מסגרת
|
<Globe className="h-4 w-4" />
|
||||||
</TabsTrigger>
|
תחום
|
||||||
)}
|
</TabsTrigger>
|
||||||
{canShowFieldTab && (
|
|
||||||
<TabsTrigger value="field" className="flex items-center gap-2">
|
|
||||||
<Globe className="h-4 w-4" />
|
|
||||||
תחום
|
|
||||||
</TabsTrigger>
|
|
||||||
)}
|
|
||||||
<TabsTrigger value="global" className="flex items-center gap-2">
|
<TabsTrigger value="global" className="flex items-center gap-2">
|
||||||
<Globe className="h-4 w-4" />
|
<Globe className="h-4 w-4" />
|
||||||
כללי
|
כללי
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
</TabsList>
|
</TabsList>
|
||||||
|
|
||||||
{canShowTeamTab && (
|
|
||||||
<TabsContent value="team" className="space-y-6">
|
<TabsContent value="team" className="space-y-6">
|
||||||
<div className="grid md:grid-cols-2 gap-6">
|
<div className="grid md:grid-cols-2 gap-6">
|
||||||
<Card>
|
<Card>
|
||||||
@@ -1343,9 +1278,7 @@ export default function AdminPage() {
|
|||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
)}
|
|
||||||
|
|
||||||
{canShowDepartmentTab && (
|
|
||||||
<TabsContent value="department" className="space-y-6">
|
<TabsContent value="department" className="space-y-6">
|
||||||
<div className="grid md:grid-cols-2 gap-6">
|
<div className="grid md:grid-cols-2 gap-6">
|
||||||
<Card>
|
<Card>
|
||||||
@@ -1410,9 +1343,7 @@ export default function AdminPage() {
|
|||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
)}
|
|
||||||
|
|
||||||
{canShowFieldTab && (
|
|
||||||
<TabsContent value="field" className="space-y-6">
|
<TabsContent value="field" className="space-y-6">
|
||||||
<div className="grid md:grid-cols-2 gap-6">
|
<div className="grid md:grid-cols-2 gap-6">
|
||||||
<Card>
|
<Card>
|
||||||
@@ -1477,7 +1408,6 @@ export default function AdminPage() {
|
|||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
)}
|
|
||||||
|
|
||||||
<TabsContent value="global" className="space-y-6">
|
<TabsContent value="global" className="space-y-6">
|
||||||
<div className="grid md:grid-cols-2 gap-6">
|
<div className="grid md:grid-cols-2 gap-6">
|
||||||
@@ -1551,8 +1481,6 @@ export default function AdminPage() {
|
|||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
{newUser.role !== "field_admin" && (
|
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="department">מסגרת</Label>
|
<Label htmlFor="department">מסגרת</Label>
|
||||||
<Select
|
<Select
|
||||||
@@ -1571,9 +1499,6 @@ export default function AdminPage() {
|
|||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
{newUser.role !== "field_admin" && newUser.role !== "department_admin" && (
|
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="team">צוות</Label>
|
<Label htmlFor="team">צוות</Label>
|
||||||
<Select value={newUser.team} onValueChange={(value) => setNewUser({ ...newUser, team: value })}>
|
<Select value={newUser.team} onValueChange={(value) => setNewUser({ ...newUser, team: value })}>
|
||||||
@@ -1589,21 +1514,15 @@ export default function AdminPage() {
|
|||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="role">הרשאה</Label>
|
<Label htmlFor="role">הרשאה</Label>
|
||||||
<Select
|
<Select
|
||||||
value={newUser.role}
|
value={newUser.role}
|
||||||
onValueChange={(value) =>
|
onValueChange={(value) =>
|
||||||
setNewUser((prev) => {
|
setNewUser({
|
||||||
const next = { ...prev, role: value, isAdmin: value !== "user" }
|
...newUser,
|
||||||
if (value === "field_admin") {
|
role: value,
|
||||||
next.department = ""
|
isAdmin: value !== "user", // Automatically set isAdmin
|
||||||
next.team = ""
|
|
||||||
} else if (value === "department_admin") {
|
|
||||||
next.team = ""
|
|
||||||
}
|
|
||||||
return next
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@@ -1939,7 +1858,7 @@ export default function AdminPage() {
|
|||||||
<br/>
|
<br/>
|
||||||
גרסה: {process.env.APPVERSION || "לא הוצהר ב-Dockerfile!"}
|
גרסה: {process.env.APPVERSION || "לא הוצהר ב-Dockerfile!"}
|
||||||
<br/>
|
<br/>
|
||||||
2026 COPYRIGHT TR-WEB
|
2025 COPYRIGHT TR-WEB
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -21,52 +21,44 @@ export async function POST(request: NextRequest) {
|
|||||||
const { name, isAdmin, field, department, team, role } = await request.json()
|
const { name, isAdmin, field, department, team, role } = await request.json()
|
||||||
|
|
||||||
// Input validation
|
// Input validation
|
||||||
if (!name || !field) {
|
if (!name || !field || !department || !team) {
|
||||||
return NextResponse.json({ error: "Invalid name or field." }, { status: 400 })
|
return NextResponse.json({ error: "נתונים חסרים" }, { status: 400 })
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate field against managed types
|
// Validate department, team, and field against managed types
|
||||||
if (!(await hasManagedType("field", field))) {
|
if (!(await hasManagedType("field", field))) {
|
||||||
return NextResponse.json({ error: "Invalid field." }, { status: 400 })
|
return NextResponse.json({ error: "Invalid field." }, { status: 400 })
|
||||||
}
|
}
|
||||||
|
|
||||||
const normalizedDepartment = typeof department === "string" && department.trim() ? department.trim() : null
|
if (!(await hasManagedType("department", department))) {
|
||||||
|
|
||||||
if (normalizedDepartment && !(await hasManagedType("department", normalizedDepartment))) {
|
|
||||||
return NextResponse.json({ error: "Invalid department." }, { status: 400 })
|
return NextResponse.json({ error: "Invalid department." }, { status: 400 })
|
||||||
}
|
}
|
||||||
|
|
||||||
const normalizedTeam = typeof team === "string" && team.trim() ? team.trim() : null
|
if (!(await hasManagedType("team", team))) {
|
||||||
|
|
||||||
if (normalizedTeam && !(await hasManagedType("team", normalizedTeam))) {
|
|
||||||
return NextResponse.json({ error: "Invalid team." }, { status: 400 })
|
return NextResponse.json({ error: "Invalid team." }, { status: 400 })
|
||||||
}
|
}
|
||||||
|
|
||||||
const fieldRows = (await safeQuery("SELECT id FROM managed_types WHERE type = 'field' AND name = ?", [
|
const fieldRows = (await safeQuery("SELECT id FROM managed_types WHERE type = 'field' AND name = ?", [
|
||||||
field,
|
field,
|
||||||
])) as Array<{ id: number }>
|
])) as Array<{ id: number }>
|
||||||
const departmentRows = normalizedDepartment
|
const departmentRows = (await safeQuery(
|
||||||
? ((await safeQuery(
|
"SELECT id, parent_id AS parentId FROM managed_types WHERE type = 'department' AND name = ?",
|
||||||
"SELECT id, parent_id AS parentId FROM managed_types WHERE type = 'department' AND name = ?",
|
[department],
|
||||||
[normalizedDepartment],
|
)) as Array<{ id: number; parentId: number | null }>
|
||||||
)) as Array<{ id: number; parentId: number | null }>)
|
const teamRows = (await safeQuery(
|
||||||
: []
|
"SELECT id, parent_id AS parentId FROM managed_types WHERE type = 'team' AND name = ?",
|
||||||
const teamRows = normalizedTeam
|
[team],
|
||||||
? ((await safeQuery(
|
)) as Array<{ id: number; parentId: number | null }>
|
||||||
"SELECT id, parent_id AS parentId FROM managed_types WHERE type = 'team' AND name = ?",
|
|
||||||
[normalizedTeam],
|
|
||||||
)) as Array<{ id: number; parentId: number | null }>)
|
|
||||||
: []
|
|
||||||
|
|
||||||
if (fieldRows.length === 0 || (normalizedDepartment && departmentRows.length === 0) || (normalizedTeam && teamRows.length === 0)) {
|
if (fieldRows.length === 0 || departmentRows.length === 0 || teamRows.length === 0) {
|
||||||
return NextResponse.json({ error: "Invalid field, department, or team." }, { status: 400 })
|
return NextResponse.json({ error: "Invalid field, department, or team." }, { status: 400 })
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalizedDepartment && departmentRows[0].parentId !== fieldRows[0].id) {
|
if (departmentRows[0].parentId !== fieldRows[0].id) {
|
||||||
return NextResponse.json({ error: "Department does not belong to field." }, { status: 400 })
|
return NextResponse.json({ error: "Department does not belong to field." }, { status: 400 })
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalizedTeam && normalizedDepartment && teamRows[0].parentId !== departmentRows[0].id) {
|
if (teamRows[0].parentId !== departmentRows[0].id) {
|
||||||
return NextResponse.json({ error: "Team does not belong to department." }, { status: 400 })
|
return NextResponse.json({ error: "Team does not belong to department." }, { status: 400 })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,21 +68,7 @@ export async function POST(request: NextRequest) {
|
|||||||
const userRole: UserRole = (role as UserRole) || (isAdmin ? "global_admin" : "user")
|
const userRole: UserRole = (role as UserRole) || (isAdmin ? "global_admin" : "user")
|
||||||
|
|
||||||
if (!validRoles.includes(userRole)) {
|
if (!validRoles.includes(userRole)) {
|
||||||
return NextResponse.json({ error: "Invalid role." }, { status: 400 })
|
return NextResponse.json({ error: "תפקיד לא תקין" }, { status: 400 })
|
||||||
}
|
|
||||||
|
|
||||||
if (userRole === "field_admin") {
|
|
||||||
if (!field || normalizedDepartment || normalizedTeam) {
|
|
||||||
return NextResponse.json({ error: "Field admins must have a field only." }, { status: 400 })
|
|
||||||
}
|
|
||||||
} else if (userRole === "department_admin") {
|
|
||||||
if (!field || !normalizedDepartment || normalizedTeam) {
|
|
||||||
return NextResponse.json({ error: "Department admins must have field + department only." }, { status: 400 })
|
|
||||||
}
|
|
||||||
} else if (userRole === "team_admin" || userRole === "user") {
|
|
||||||
if (!field || !normalizedDepartment || !normalizedTeam) {
|
|
||||||
return NextResponse.json({ error: "Team/users require field, department, and team." }, { status: 400 })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate unique Login ID
|
// Generate unique Login ID
|
||||||
@@ -102,7 +80,7 @@ export async function POST(request: NextRequest) {
|
|||||||
|
|
||||||
await safeQuery(
|
await safeQuery(
|
||||||
"INSERT INTO users (national_id, password, name, is_admin, role, must_change_password, field, department, team) VALUES (?, ?, ?, ?, ?, TRUE, ?, ?, ?)",
|
"INSERT INTO users (national_id, password, name, is_admin, role, must_change_password, field, department, team) VALUES (?, ?, ?, ?, ?, TRUE, ?, ?, ?)",
|
||||||
[nationalId, hashedPassword, name, isAdmin, userRole, field, normalizedDepartment, normalizedTeam],
|
[nationalId, hashedPassword, name, isAdmin, userRole, field, department, team],
|
||||||
)
|
)
|
||||||
|
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export async function POST(request: NextRequest) {
|
|||||||
|
|
||||||
// Get admin's field and department
|
// Get admin's field and department
|
||||||
const adminData = (await safeQuery(
|
const adminData = (await safeQuery(
|
||||||
"SELECT role, field, department FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'",
|
"SELECT field, department FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'",
|
||||||
[adminId],
|
[adminId],
|
||||||
)) as any[]
|
)) as any[]
|
||||||
|
|
||||||
@@ -19,14 +19,10 @@ export async function POST(request: NextRequest) {
|
|||||||
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
|
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
|
||||||
}
|
}
|
||||||
|
|
||||||
const { role: adminRole, field: adminField, department: adminDepartment } = adminData[0]
|
const { field: adminField, department: adminDepartment } = adminData[0]
|
||||||
|
|
||||||
if (adminRole !== "department_admin" && adminRole !== "global_admin") {
|
|
||||||
return NextResponse.json({ error: "Insufficient permissions." }, { status: 403 })
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!adminField || !adminDepartment) {
|
if (!adminField || !adminDepartment) {
|
||||||
return NextResponse.json({ error: "Department is not assigned." }, { status: 400 })
|
return NextResponse.json({ error: "למנהל לא הוגדרו תחום ומסגרת" }, { status: 400 })
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check cooldown for department resets
|
// Check cooldown for department resets
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export async function POST(request: Request) {
|
|||||||
|
|
||||||
// Get admin's field and department
|
// Get admin's field and department
|
||||||
const adminData = (await executeQuery(
|
const adminData = (await executeQuery(
|
||||||
"SELECT role, field, department FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'",
|
"SELECT field, department FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'",
|
||||||
[adminId],
|
[adminId],
|
||||||
)) as any[]
|
)) as any[]
|
||||||
|
|
||||||
@@ -19,18 +19,10 @@ export async function POST(request: Request) {
|
|||||||
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
|
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
|
||||||
}
|
}
|
||||||
|
|
||||||
const { role: adminRole, field: adminField, department: adminDepartment } = adminData[0]
|
const { field: adminField, department: adminDepartment } = adminData[0]
|
||||||
|
|
||||||
if (adminRole !== "department_admin" && adminRole !== "global_admin" || !adminField || !adminDepartment) {
|
if (!adminField || !adminDepartment) {
|
||||||
return NextResponse.json({
|
return NextResponse.json({ error: "למנהל לא הוגדרו תחום ומסגרת" }, { status: 400 })
|
||||||
no_report: 0,
|
|
||||||
in_shelter: 0,
|
|
||||||
not_in_shelter: 0,
|
|
||||||
no_alarm: 0,
|
|
||||||
safe_after_exit: 0,
|
|
||||||
field: adminField,
|
|
||||||
department: adminDepartment,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get department stats with field and department context
|
// Get department stats with field and department context
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export async function POST(request: NextRequest) {
|
|||||||
|
|
||||||
// Get admin's field and department
|
// Get admin's field and department
|
||||||
const adminData = (await executeQuery(
|
const adminData = (await executeQuery(
|
||||||
"SELECT role, field, department FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'",
|
"SELECT field, department FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'",
|
||||||
[adminId],
|
[adminId],
|
||||||
)) as any[]
|
)) as any[]
|
||||||
|
|
||||||
@@ -19,10 +19,10 @@ export async function POST(request: NextRequest) {
|
|||||||
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
|
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
|
||||||
}
|
}
|
||||||
|
|
||||||
const { role: adminRole, field: adminField, department: adminDepartment } = adminData[0]
|
const { field: adminField, department: adminDepartment } = adminData[0]
|
||||||
|
|
||||||
if (adminRole !== "department_admin" && adminRole !== "global_admin" || !adminField || !adminDepartment) {
|
if (!adminField || !adminDepartment) {
|
||||||
return NextResponse.json([])
|
return NextResponse.json({ error: "למנהל לא הוגדרו תחום ומסגרת" }, { status: 400 })
|
||||||
}
|
}
|
||||||
|
|
||||||
let query = ""
|
let query = ""
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export async function POST(request: Request) {
|
|||||||
|
|
||||||
// Get admin's field and department
|
// Get admin's field and department
|
||||||
const adminData = (await executeQuery(
|
const adminData = (await executeQuery(
|
||||||
"SELECT role, field, department FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'",
|
"SELECT field, department FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'",
|
||||||
[adminId],
|
[adminId],
|
||||||
)) as any[]
|
)) as any[]
|
||||||
|
|
||||||
@@ -19,10 +19,10 @@ export async function POST(request: Request) {
|
|||||||
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
|
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
|
||||||
}
|
}
|
||||||
|
|
||||||
const { role: adminRole, field: adminField, department: adminDepartment } = adminData[0]
|
const { field: adminField, department: adminDepartment } = adminData[0]
|
||||||
|
|
||||||
if (adminRole !== "department_admin" && adminRole !== "global_admin" || !adminField || !adminDepartment) {
|
if (!adminField || !adminDepartment) {
|
||||||
return NextResponse.json({ users: [], field: adminField, department: adminDepartment })
|
return NextResponse.json({ error: "למנהל לא הוגדרו תחום ומסגרת" }, { status: 400 })
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get department users with field and department context
|
// Get department users with field and department context
|
||||||
@@ -31,7 +31,6 @@ export async function POST(request: Request) {
|
|||||||
SELECT
|
SELECT
|
||||||
national_id,
|
national_id,
|
||||||
name,
|
name,
|
||||||
role,
|
|
||||||
in_shelter,
|
in_shelter,
|
||||||
last_updated,
|
last_updated,
|
||||||
is_admin,
|
is_admin,
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ export async function POST(request: Request) {
|
|||||||
SELECT
|
SELECT
|
||||||
national_id,
|
national_id,
|
||||||
name,
|
name,
|
||||||
role,
|
|
||||||
in_shelter,
|
in_shelter,
|
||||||
last_updated,
|
last_updated,
|
||||||
is_admin,
|
is_admin,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export async function POST(request: NextRequest) {
|
|||||||
|
|
||||||
// Get admin's field, department, and team
|
// Get admin's field, department, and team
|
||||||
const adminData = (await safeQuery(
|
const adminData = (await safeQuery(
|
||||||
"SELECT role, field, department, team FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'",
|
"SELECT field, department, team FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'",
|
||||||
[adminId],
|
[adminId],
|
||||||
)) as any[]
|
)) as any[]
|
||||||
|
|
||||||
@@ -20,14 +20,10 @@ export async function POST(request: NextRequest) {
|
|||||||
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
|
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
|
||||||
}
|
}
|
||||||
|
|
||||||
const { role: adminRole, field: adminField, department: adminDepartment, team: adminTeam } = adminData[0]
|
const { field: adminField, department: adminDepartment, team: adminTeam } = adminData[0]
|
||||||
|
|
||||||
if (adminRole !== "team_admin" && adminRole !== "global_admin") {
|
|
||||||
return NextResponse.json({ error: "Insufficient permissions." }, { status: 403 })
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!adminField || !adminDepartment || !adminTeam) {
|
if (!adminField || !adminDepartment || !adminTeam) {
|
||||||
return NextResponse.json({ error: "Team is not assigned." }, { status: 400 })
|
return NextResponse.json({ error: "למנהל לא הוגדרו תחום, מסגרת וצוות" }, { status: 400 })
|
||||||
}
|
}
|
||||||
|
|
||||||
await safeQuery(
|
await safeQuery(
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export async function POST(request: Request) {
|
|||||||
|
|
||||||
// Get admin's field, department, and team
|
// Get admin's field, department, and team
|
||||||
const adminData = (await executeQuery(
|
const adminData = (await executeQuery(
|
||||||
"SELECT role, field, department, team FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'",
|
"SELECT field, department, team FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'",
|
||||||
[adminId],
|
[adminId],
|
||||||
)) as any[]
|
)) as any[]
|
||||||
|
|
||||||
@@ -19,19 +19,10 @@ export async function POST(request: Request) {
|
|||||||
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
|
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
|
||||||
}
|
}
|
||||||
|
|
||||||
const { role: adminRole, field: adminField, department: adminDepartment, team: adminTeam } = adminData[0]
|
const { field: adminField, department: adminDepartment, team: adminTeam } = adminData[0]
|
||||||
|
|
||||||
if (adminRole !== "team_admin" && adminRole !== "global_admin" || !adminField || !adminDepartment || !adminTeam) {
|
if (!adminField || !adminDepartment || !adminTeam) {
|
||||||
return NextResponse.json({
|
return NextResponse.json({ error: "למנהל לא הוגדרו תחום, מסגרת וצוות" }, { status: 400 })
|
||||||
no_report: 0,
|
|
||||||
in_shelter: 0,
|
|
||||||
not_in_shelter: 0,
|
|
||||||
no_alarm: 0,
|
|
||||||
safe_after_exit: 0,
|
|
||||||
field: adminField,
|
|
||||||
department: adminDepartment,
|
|
||||||
team: adminTeam,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get team stats with full context (field + department + team)
|
// Get team stats with full context (field + department + team)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export async function POST(request: NextRequest) {
|
|||||||
|
|
||||||
// Get admin's field, department, and team
|
// Get admin's field, department, and team
|
||||||
const adminData = (await executeQuery(
|
const adminData = (await executeQuery(
|
||||||
"SELECT role, field, department, team FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'",
|
"SELECT field, department, team FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'",
|
||||||
[adminId],
|
[adminId],
|
||||||
)) as any[]
|
)) as any[]
|
||||||
|
|
||||||
@@ -19,10 +19,10 @@ export async function POST(request: NextRequest) {
|
|||||||
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
|
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
|
||||||
}
|
}
|
||||||
|
|
||||||
const { role: adminRole, field: adminField, department: adminDepartment, team: adminTeam } = adminData[0]
|
const { field: adminField, department: adminDepartment, team: adminTeam } = adminData[0]
|
||||||
|
|
||||||
if (adminRole !== "team_admin" && adminRole !== "global_admin" || !adminField || !adminDepartment || !adminTeam) {
|
if (!adminField || !adminDepartment || !adminTeam) {
|
||||||
return NextResponse.json([])
|
return NextResponse.json({ error: "למנהל לא הוגדרו תחום, מסגרת וצוות" }, { status: 400 })
|
||||||
}
|
}
|
||||||
|
|
||||||
let query = ""
|
let query = ""
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export async function POST(request: Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get admin's field, department, and team
|
// Get admin's field, department, and team
|
||||||
const adminData = (await executeQuery("SELECT role, field, department, team FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'", [
|
const adminData = (await executeQuery("SELECT field, department, team FROM users WHERE national_id = ? AND role IS NOT NULL AND role != 'user'", [
|
||||||
adminId,
|
adminId,
|
||||||
])) as any[]
|
])) as any[]
|
||||||
|
|
||||||
@@ -18,10 +18,10 @@ export async function POST(request: Request) {
|
|||||||
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
|
return NextResponse.json({ error: "מנהל לא נמצא" }, { status: 404 })
|
||||||
}
|
}
|
||||||
|
|
||||||
const { role: adminRole, field: adminField, department: adminDepartment, team: adminTeam } = adminData[0]
|
const { field: adminField, department: adminDepartment, team: adminTeam } = adminData[0]
|
||||||
|
|
||||||
if (adminRole !== "team_admin" && adminRole !== "global_admin" || !adminField || !adminDepartment || !adminTeam) {
|
if (!adminField || !adminDepartment || !adminTeam) {
|
||||||
return NextResponse.json({ users: [], field: adminField, department: adminDepartment, team: adminTeam })
|
return NextResponse.json({ error: "למנהל לא הוגדרו תחום, מסגרת וצוות" }, { status: 400 })
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get team users with full context (field + department + team)
|
// Get team users with full context (field + department + team)
|
||||||
@@ -30,7 +30,6 @@ export async function POST(request: Request) {
|
|||||||
SELECT
|
SELECT
|
||||||
national_id,
|
national_id,
|
||||||
name,
|
name,
|
||||||
role,
|
|
||||||
in_shelter,
|
in_shelter,
|
||||||
last_updated,
|
last_updated,
|
||||||
is_admin,
|
is_admin,
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export async function POST(request: NextRequest) {
|
|||||||
try {
|
try {
|
||||||
const { adminId, targetUserId, field, department, team } = await request.json()
|
const { adminId, targetUserId, field, department, team } = await request.json()
|
||||||
|
|
||||||
if (!adminId || !targetUserId || !field ) {
|
if (!adminId || !targetUserId || !field || !department || !team) {
|
||||||
return NextResponse.json({ error: "חסרים שדות חובה." }, { status: 400 })
|
return NextResponse.json({ error: "חסרים שדות חובה." }, { status: 400 })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ export async function POST(request: NextRequest) {
|
|||||||
|
|
||||||
const admin = adminRows[0]
|
const admin = adminRows[0]
|
||||||
|
|
||||||
const userRows = (await safeQuery("SELECT national_id, role, field, department, team FROM users WHERE national_id = ?", [
|
const userRows = (await safeQuery("SELECT national_id, field, department, team FROM users WHERE national_id = ?", [
|
||||||
targetUserId,
|
targetUserId,
|
||||||
])) as any[]
|
])) as any[]
|
||||||
if (userRows.length === 0) {
|
if (userRows.length === 0) {
|
||||||
@@ -39,25 +39,10 @@ export async function POST(request: NextRequest) {
|
|||||||
}
|
}
|
||||||
const targetUser = userRows[0]
|
const targetUser = userRows[0]
|
||||||
|
|
||||||
const normalizedDepartment = typeof department === "string" && department.trim() ? department.trim() : null
|
|
||||||
const normalizedTeam = typeof team === "string" && team.trim() ? team.trim() : null
|
|
||||||
|
|
||||||
if (targetUser.role !== "field_admin" && !normalizedDepartment) {
|
|
||||||
return NextResponse.json({ error: "Missing required fields." }, { status: 400 })
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((targetUser.role === "team_admin" || targetUser.role === "user") && !normalizedTeam) {
|
|
||||||
return NextResponse.json({ error: "Missing required fields." }, { status: 400 })
|
|
||||||
}
|
|
||||||
|
|
||||||
const effectiveDepartment = targetUser.role === "field_admin" ? null : normalizedDepartment
|
|
||||||
const effectiveTeam = targetUser.role === "field_admin" ? null : normalizedTeam
|
|
||||||
|
|
||||||
|
|
||||||
const [fieldOk, departmentOk, teamOk] = await Promise.all([
|
const [fieldOk, departmentOk, teamOk] = await Promise.all([
|
||||||
hasManagedType("field", field),
|
hasManagedType("field", field),
|
||||||
effectiveDepartment ? hasManagedType("department", effectiveDepartment) : Promise.resolve(true),
|
hasManagedType("department", department),
|
||||||
effectiveTeam ? hasManagedType("team", effectiveTeam) : Promise.resolve(true),
|
hasManagedType("team", team),
|
||||||
])
|
])
|
||||||
|
|
||||||
if (!fieldOk || !departmentOk || !teamOk) {
|
if (!fieldOk || !departmentOk || !teamOk) {
|
||||||
@@ -67,27 +52,24 @@ export async function POST(request: NextRequest) {
|
|||||||
const fieldRows = (await safeQuery("SELECT id FROM managed_types WHERE type = 'field' AND name = ?", [
|
const fieldRows = (await safeQuery("SELECT id FROM managed_types WHERE type = 'field' AND name = ?", [
|
||||||
field,
|
field,
|
||||||
])) as Array<{ id: number }>
|
])) as Array<{ id: number }>
|
||||||
const departmentRows = effectiveDepartment
|
const departmentRows = (await safeQuery(
|
||||||
? ((await safeQuery(
|
"SELECT id, parent_id AS parentId FROM managed_types WHERE type = 'department' AND name = ?",
|
||||||
"SELECT id, parent_id AS parentId FROM managed_types WHERE type = 'department' AND name = ?",
|
[department],
|
||||||
[effectiveDepartment],
|
)) as Array<{ id: number; parentId: number | null }>
|
||||||
)) as Array<{ id: number; parentId: number | null }>)
|
const teamRows = (await safeQuery(
|
||||||
: []
|
"SELECT id, parent_id AS parentId FROM managed_types WHERE type = 'team' AND name = ?",
|
||||||
const teamRows = effectiveTeam
|
[team],
|
||||||
? ((await safeQuery("SELECT id, parent_id AS parentId FROM managed_types WHERE type = 'team' AND name = ?", [
|
)) as Array<{ id: number; parentId: number | null }>
|
||||||
effectiveTeam,
|
|
||||||
])) as Array<{ id: number; parentId: number | null }>)
|
|
||||||
: []
|
|
||||||
|
|
||||||
if (fieldRows.length === 0 || (effectiveDepartment && departmentRows.length === 0) || (effectiveTeam && teamRows.length === 0)) {
|
if (fieldRows.length === 0 || departmentRows.length === 0 || teamRows.length === 0) {
|
||||||
return NextResponse.json({ error: "תחום, מסגרת או צוות שגויים." }, { status: 400 })
|
return NextResponse.json({ error: "תחום, מסגרת או צוות שגויים." }, { status: 400 })
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effectiveDepartment && departmentRows[0].parentId !== fieldRows[0].id) {
|
if (departmentRows[0].parentId !== fieldRows[0].id) {
|
||||||
return NextResponse.json({ error: "מסגרת לא משוייכת לתחום הנבחר." }, { status: 400 })
|
return NextResponse.json({ error: "מסגרת לא משוייכת לתחום הנבחר." }, { status: 400 })
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effectiveTeam && teamRows[0].parentId !== departmentRows[0].id) {
|
if (teamRows[0].parentId !== departmentRows[0].id) {
|
||||||
return NextResponse.json({ error: "צוות לא משוייך למסגרת הנבחרת." }, { status: 400 })
|
return NextResponse.json({ error: "צוות לא משוייך למסגרת הנבחרת." }, { status: 400 })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +94,7 @@ export async function POST(request: NextRequest) {
|
|||||||
if (targetUser.team !== admin.team) {
|
if (targetUser.team !== admin.team) {
|
||||||
return NextResponse.json({ error: "המשתמש הנבחר לא משוייך לצוות שלך." }, { status: 403 })
|
return NextResponse.json({ error: "המשתמש הנבחר לא משוייך לצוות שלך." }, { status: 403 })
|
||||||
}
|
}
|
||||||
if (effectiveTeam !== admin.team) {
|
if (team !== admin.team) {
|
||||||
return NextResponse.json({ error: "מנהלי צוותים רשאים לנהל אך ורק את הצוות שלהם." }, { status: 403 })
|
return NextResponse.json({ error: "מנהלי צוותים רשאים לנהל אך ורק את הצוות שלהם." }, { status: 403 })
|
||||||
}
|
}
|
||||||
if (admin.department && department !== admin.department) {
|
if (admin.department && department !== admin.department) {
|
||||||
@@ -127,8 +109,8 @@ export async function POST(request: NextRequest) {
|
|||||||
|
|
||||||
await safeQuery("UPDATE users SET field = ?, department = ?, team = ? WHERE national_id = ?", [
|
await safeQuery("UPDATE users SET field = ?, department = ?, team = ? WHERE national_id = ?", [
|
||||||
field,
|
field,
|
||||||
effectiveDepartment,
|
department,
|
||||||
effectiveTeam,
|
team,
|
||||||
targetUserId,
|
targetUserId,
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ export async function POST(request: Request) { // Changed to POST, similar to te
|
|||||||
SELECT
|
SELECT
|
||||||
national_id,
|
national_id,
|
||||||
name,
|
name,
|
||||||
role,
|
|
||||||
in_shelter,
|
in_shelter,
|
||||||
last_updated,
|
last_updated,
|
||||||
is_admin,
|
is_admin,
|
||||||
@@ -30,4 +29,4 @@ export async function POST(request: Request) { // Changed to POST, similar to te
|
|||||||
console.error("Get users error:", error) // Error logging similar to team_users-route.ts
|
console.error("Get users error:", error) // Error logging similar to team_users-route.ts
|
||||||
return NextResponse.json({ error: "שגיאה בטעינת משתמשים" }, { status: 500 }) // Error response format similar to team_users-route.ts
|
return NextResponse.json({ error: "שגיאה בטעינת משתמשים" }, { status: 500 }) // Error response format similar to team_users-route.ts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,9 @@
|
|||||||
import { NextResponse } from "next/server"
|
import { NextResponse } from "next/server"
|
||||||
import os from "os"
|
import os from "os"
|
||||||
|
|
||||||
export const dynamic = "force-dynamic"
|
|
||||||
export const revalidate = 0
|
|
||||||
|
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
try {
|
try {
|
||||||
return NextResponse.json(
|
return NextResponse.json({ instance: os.hostname() })
|
||||||
{ instance: os.hostname() },
|
|
||||||
{ headers: { "Cache-Control": "no-store" } },
|
|
||||||
)
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Instance fetch error:", error)
|
console.error("Instance fetch error:", error)
|
||||||
return NextResponse.json({ error: "Failed to load instance name." }, { status: 500 })
|
return NextResponse.json({ error: "Failed to load instance name." }, { status: 500 })
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ export default function DashboardPage() {
|
|||||||
<br/>
|
<br/>
|
||||||
גרסה: {process.env.APPVERSION || "לא הוגדרה גרסה ב-Dockerfile!"}
|
גרסה: {process.env.APPVERSION || "לא הוגדרה גרסה ב-Dockerfile!"}
|
||||||
<br/>
|
<br/>
|
||||||
2026 COPYRIGHT TR-WEB
|
2025 COPYRIGHT TR-WEB
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
+3
-6
@@ -1,12 +1,9 @@
|
|||||||
import type React from "react"
|
import type React from "react"
|
||||||
import type { Metadata } from "next"
|
import type { Metadata } from "next"
|
||||||
import { IBM_Plex_Sans_Hebrew } from "next/font/google"
|
import { Inter } from "next/font/google"
|
||||||
import "./globals.css"
|
import "./globals.css"
|
||||||
|
|
||||||
const ibmPlexSansHebrew = IBM_Plex_Sans_Hebrew({
|
const inter = Inter({ subsets: ["latin"] })
|
||||||
subsets: ["hebrew"],
|
|
||||||
weight: ["100", "200", "300", "400", "500", "600", "700"],
|
|
||||||
})
|
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'ממ"ד',
|
title: 'ממ"ד',
|
||||||
@@ -25,7 +22,7 @@ export default function RootLayout({
|
|||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<html lang="he" dir="rtl">
|
<html lang="he" dir="rtl">
|
||||||
<body className={ibmPlexSansHebrew.className}>{children}</body>
|
<body className={inter.className}>{children}</body>
|
||||||
</html>
|
</html>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ interface ManagedTypeOption {
|
|||||||
interface UserScopeModalUser {
|
interface UserScopeModalUser {
|
||||||
national_id: string
|
national_id: string
|
||||||
name: string
|
name: string
|
||||||
role?: string
|
|
||||||
field?: string
|
field?: string
|
||||||
department?: string
|
department?: string
|
||||||
team?: string
|
team?: string
|
||||||
@@ -45,18 +44,12 @@ export function UserScopeModal({
|
|||||||
const [field, setField] = useState("")
|
const [field, setField] = useState("")
|
||||||
const [department, setDepartment] = useState("")
|
const [department, setDepartment] = useState("")
|
||||||
const [team, setTeam] = useState("")
|
const [team, setTeam] = useState("")
|
||||||
const noDepartmentValue = "__no_department__"
|
|
||||||
const noTeamValue = "__no_team__"
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (user && isOpen) {
|
if (user && isOpen) {
|
||||||
setField(user.field || "")
|
setField(user.field || "")
|
||||||
if (user.role === "field_admin") {
|
setDepartment(user.department || "")
|
||||||
setDepartment(user.department || noDepartmentValue)
|
setTeam(user.team || "")
|
||||||
} else {
|
|
||||||
setDepartment(user.department || "")
|
|
||||||
}
|
|
||||||
setTeam(user.team || noTeamValue)
|
|
||||||
}
|
}
|
||||||
}, [user, isOpen])
|
}, [user, isOpen])
|
||||||
|
|
||||||
@@ -65,30 +58,25 @@ export function UserScopeModal({
|
|||||||
? departments.filter((item) => item.parentId === selectedFieldId)
|
? departments.filter((item) => item.parentId === selectedFieldId)
|
||||||
: departments
|
: departments
|
||||||
const selectedDepartmentId = departments.find((item) => item.name === department)?.id
|
const selectedDepartmentId = departments.find((item) => item.name === department)?.id
|
||||||
const availableTeams =
|
const availableTeams = selectedDepartmentId
|
||||||
selectedDepartmentId && department !== noDepartmentValue
|
? teams.filter((item) => item.parentId === selectedDepartmentId)
|
||||||
? teams.filter((item) => item.parentId === selectedDepartmentId)
|
: teams
|
||||||
: []
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (field && availableDepartments.length > 0) {
|
if (field && availableDepartments.length > 0) {
|
||||||
const hasDepartment = availableDepartments.some((item) => item.name === department)
|
const hasDepartment = availableDepartments.some((item) => item.name === department)
|
||||||
if (!hasDepartment) {
|
if (!hasDepartment) {
|
||||||
setDepartment(user?.role === "field_admin" ? noDepartmentValue : "")
|
setDepartment("")
|
||||||
setTeam(noTeamValue)
|
setTeam("")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [field, availableDepartments, department])
|
}, [field, availableDepartments, department])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (department === noDepartmentValue) {
|
|
||||||
setTeam(noTeamValue)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (department && availableTeams.length > 0) {
|
if (department && availableTeams.length > 0) {
|
||||||
const hasTeam = availableTeams.some((item) => item.name === team)
|
const hasTeam = availableTeams.some((item) => item.name === team)
|
||||||
if (!hasTeam) {
|
if (!hasTeam) {
|
||||||
setTeam(noTeamValue)
|
setTeam("")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [department, availableTeams, team])
|
}, [department, availableTeams, team])
|
||||||
@@ -96,16 +84,8 @@ export function UserScopeModal({
|
|||||||
if (!user) return null
|
if (!user) return null
|
||||||
|
|
||||||
const handleSave = async () => {
|
const handleSave = async () => {
|
||||||
if (!field) return
|
if (!field || !department || !team) return
|
||||||
const normalizedDepartment = department === noDepartmentValue ? "" : department
|
await onSave({ userId: user.national_id, field, department, team })
|
||||||
const normalizedTeam = team === noTeamValue ? "" : team
|
|
||||||
const scopedDepartment = user.role === "field_admin" ? "" : normalizedDepartment
|
|
||||||
const scopedTeam = user.role === "field_admin" ? "" : normalizedTeam
|
|
||||||
|
|
||||||
if (user.role !== "field_admin" && !scopedDepartment) return
|
|
||||||
if ((user.role === "team_admin" || user.role === "user") && !scopedTeam) return
|
|
||||||
|
|
||||||
await onSave({ userId: user.national_id, field, department: scopedDepartment, team: scopedTeam })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -124,7 +104,7 @@ export function UserScopeModal({
|
|||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Select value={field} onValueChange={setField}>
|
<Select value={field} onValueChange={setField}>
|
||||||
<SelectTrigger dir="rtl">
|
<SelectTrigger dir="rtl">
|
||||||
<SelectValue placeholder="??? ????" />
|
<SelectValue placeholder="בחרו תחום" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent dir="rtl">
|
<SelectContent dir="rtl">
|
||||||
{fields.map((item) => (
|
{fields.map((item) => (
|
||||||
@@ -139,7 +119,7 @@ export function UserScopeModal({
|
|||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Select value={department} onValueChange={setDepartment}>
|
<Select value={department} onValueChange={setDepartment}>
|
||||||
<SelectTrigger dir="rtl">
|
<SelectTrigger dir="rtl">
|
||||||
<SelectValue placeholder="??? ?????" />
|
<SelectValue placeholder="בחרו מסגרת" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent dir="rtl">
|
<SelectContent dir="rtl">
|
||||||
{availableDepartments.map((item) => (
|
{availableDepartments.map((item) => (
|
||||||
@@ -147,9 +127,6 @@ export function UserScopeModal({
|
|||||||
{item.name}
|
{item.name}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
{user.role === "field_admin" && (
|
|
||||||
<SelectItem value={noDepartmentValue}>??? ?????</SelectItem>
|
|
||||||
)}
|
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
@@ -157,7 +134,7 @@ export function UserScopeModal({
|
|||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Select value={team} onValueChange={setTeam}>
|
<Select value={team} onValueChange={setTeam}>
|
||||||
<SelectTrigger dir="rtl">
|
<SelectTrigger dir="rtl">
|
||||||
<SelectValue placeholder="??? ????" />
|
<SelectValue placeholder="בחרו צוות" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent dir="rtl">
|
<SelectContent dir="rtl">
|
||||||
{availableTeams.map((item) => (
|
{availableTeams.map((item) => (
|
||||||
@@ -165,7 +142,6 @@ export function UserScopeModal({
|
|||||||
{item.name}
|
{item.name}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
<SelectItem value={noTeamValue}>ללא צוות</SelectItem>
|
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
@@ -177,12 +153,7 @@ export function UserScopeModal({
|
|||||||
<Button
|
<Button
|
||||||
onClick={handleSave}
|
onClick={handleSave}
|
||||||
className="w-full"
|
className="w-full"
|
||||||
disabled={
|
disabled={isSaving || !field || !department || !team}
|
||||||
isSaving ||
|
|
||||||
!field ||
|
|
||||||
(user.role !== "field_admin" && !department) ||
|
|
||||||
((user.role === "team_admin" || user.role === "user") && !team)
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{isSaving ? "שומר..." : "שמירה"}
|
{isSaving ? "שומר..." : "שמירה"}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
env: {
|
env: {
|
||||||
APPVERSION: '1.1.4'
|
APPVERSION: '1.1.0'
|
||||||
},
|
},
|
||||||
experimental: {
|
experimental: {
|
||||||
serverComponentsExternalPackages: ['mysql2']
|
serverComponentsExternalPackages: ['mysql2']
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mamad-app",
|
"name": "mamad-app",
|
||||||
"version": "1.1.4",
|
"version": "1.0.4",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
@layer utilities {
|
@layer utilities {
|
||||||
.text-balance {
|
.text-balance {
|
||||||
|
|||||||
Reference in New Issue
Block a user