managment frontend initiated
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import { loginSelectEmployee } from "@/apicalls/login/login";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Company } from "./types";
|
||||
|
||||
interface LoginEmployeeProps {
|
||||
selectionList: Company[];
|
||||
lang?: "en" | "tr";
|
||||
onSelect?: (uu_id: string) => void;
|
||||
}
|
||||
|
||||
// Language dictionary for internationalization
|
||||
const languageDictionary = {
|
||||
tr: {
|
||||
companySelection: "Şirket Seçimi",
|
||||
loggedInAs: "Çalışan olarak giriş yaptınız",
|
||||
duty: "Görev",
|
||||
id: "Kimlik",
|
||||
noSelections: "Seçenek bulunamadı",
|
||||
},
|
||||
en: {
|
||||
companySelection: "Select your company",
|
||||
loggedInAs: "You are logged in as an employee",
|
||||
duty: "Duty",
|
||||
id: "ID",
|
||||
noSelections: "No selections available",
|
||||
},
|
||||
};
|
||||
|
||||
function LoginEmployee({
|
||||
selectionList,
|
||||
lang = "en",
|
||||
onSelect,
|
||||
}: LoginEmployeeProps) {
|
||||
const t = languageDictionary[lang] || languageDictionary.en;
|
||||
const router = useRouter();
|
||||
|
||||
const handleSelect = (uu_id: string) => {
|
||||
console.log("Selected employee uu_id:", uu_id);
|
||||
|
||||
// If an external onSelect handler is provided, use it
|
||||
if (onSelect) {
|
||||
onSelect(uu_id);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise use the internal handler
|
||||
loginSelectEmployee({ company_uu_id: uu_id })
|
||||
.then((responseData: any) => {
|
||||
if (responseData?.status === 200 || responseData?.status === 202) {
|
||||
router.push("/dashboard");
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="text-2xl font-bold">{t.companySelection}</div>
|
||||
<div className="text-sm text-gray-500 mt-4">{t.loggedInAs}</div>
|
||||
|
||||
{Array.isArray(selectionList) && selectionList.length === 0 && (
|
||||
<div className="text-center p-4">{t.noSelections}</div>
|
||||
)}
|
||||
|
||||
{Array.isArray(selectionList) && selectionList.length === 1 && (
|
||||
<div className="w-full p-4 m-2 bg-emerald-300 rounded-lg">
|
||||
<div className="flex flex-col items-center md:items-start">
|
||||
<div>
|
||||
<span className="text-2xl font-medium">
|
||||
{selectionList[0].public_name}
|
||||
</span>
|
||||
{selectionList[0].company_type && (
|
||||
<span className="ml-2 font-medium text-sky-500">
|
||||
{selectionList[0].company_type}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{selectionList[0].duty && (
|
||||
<div className="mt-1">
|
||||
<span className="text-md font-medium text-gray-700">
|
||||
{t.duty}: {selectionList[0].duty}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="mt-2">
|
||||
<span className="flex gap-2 font-medium text-gray-600 dark:text-gray-400 text-sm">
|
||||
<span>
|
||||
{t.id}: {selectionList[0].uu_id}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-3">
|
||||
<button
|
||||
className="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors"
|
||||
onClick={() => handleSelect(selectionList[0].uu_id)}
|
||||
>
|
||||
Continue
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{Array.isArray(selectionList) &&
|
||||
selectionList.length > 1 &&
|
||||
selectionList.map((item: Company, index: number) => (
|
||||
<div
|
||||
key={index}
|
||||
className="w-full p-4 m-2 bg-emerald-300 hover:bg-emerald-500 rounded-lg transition-colors duration-200 cursor-pointer"
|
||||
onClick={() => handleSelect(item.uu_id)}
|
||||
>
|
||||
<div className="flex flex-col items-center md:items-start">
|
||||
<div>
|
||||
<span className="text-2xl font-medium">{item.public_name}</span>
|
||||
{item.company_type && (
|
||||
<span className="ml-2 font-medium text-sky-500">
|
||||
{item.company_type}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{item.duty && (
|
||||
<div className="mt-1">
|
||||
<span className="text-md font-medium text-gray-700">
|
||||
{t.duty}: {item.duty}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="mt-2">
|
||||
<span className="flex gap-2 font-medium text-gray-600 dark:text-gray-400 text-sm">
|
||||
<span>
|
||||
{t.id}: {item.uu_id}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default LoginEmployee;
|
||||
@@ -0,0 +1,111 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import { loginSelectOccupant } from "@/apicalls/login/login";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { BuildingMap } from "./types";
|
||||
|
||||
interface LoginOccupantProps {
|
||||
selectionList: BuildingMap;
|
||||
lang?: "en" | "tr";
|
||||
}
|
||||
|
||||
// Language dictionary for internationalization
|
||||
const languageDictionary = {
|
||||
tr: {
|
||||
occupantSelection: "Daire Seçimi",
|
||||
loggedInAs: "Kiracı olarak giriş yaptınız",
|
||||
buildingInfo: "Bina Bilgisi",
|
||||
level: "Kat",
|
||||
noSelections: "Seçenek bulunamadı",
|
||||
},
|
||||
en: {
|
||||
occupantSelection: "Select your occupant type",
|
||||
loggedInAs: "You are logged in as an occupant",
|
||||
buildingInfo: "Building Info",
|
||||
level: "Level",
|
||||
noSelections: "No selections available",
|
||||
},
|
||||
};
|
||||
|
||||
function LoginOccupant({
|
||||
selectionList,
|
||||
lang = "en"
|
||||
}: LoginOccupantProps) {
|
||||
const t = languageDictionary[lang] || languageDictionary.en;
|
||||
const router = useRouter();
|
||||
|
||||
const handleSelect = (uu_id: string) => {
|
||||
console.log("Selected occupant uu_id:", uu_id);
|
||||
|
||||
loginSelectOccupant({
|
||||
build_living_space_uu_id: uu_id,
|
||||
})
|
||||
.then((responseData: any) => {
|
||||
if (responseData?.status === 200 || responseData?.status === 202) {
|
||||
router.push("/dashboard");
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="text-2xl font-bold">{t.occupantSelection}</div>
|
||||
<div className="text-sm text-gray-500 mt-4">
|
||||
{t.loggedInAs}
|
||||
</div>
|
||||
{selectionList && Object.keys(selectionList).length > 0 ? (
|
||||
Object.keys(selectionList).map((buildKey: string) => {
|
||||
const building = selectionList[buildKey];
|
||||
return (
|
||||
<div key={buildKey} className="mb-6">
|
||||
<div className="w-full p-3 bg-blue-100 rounded-t-lg">
|
||||
<h3 className="text-lg font-medium text-blue-800">
|
||||
<span className="mr-1">{t.buildingInfo}:</span>
|
||||
{building.build_name} - No: {building.build_no}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2 mt-2">
|
||||
{building.occupants.map((occupant: any, idx: number) => (
|
||||
<div
|
||||
key={`${buildKey}-${idx}`}
|
||||
className="w-full p-4 bg-emerald-300 hover:bg-emerald-500 rounded-lg transition-colors duration-200 cursor-pointer"
|
||||
onClick={() => handleSelect(occupant.build_living_space_uu_id)}
|
||||
>
|
||||
<div className="flex flex-col">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-xl font-medium">
|
||||
{occupant.description}
|
||||
</span>
|
||||
<span className="text-sm font-medium bg-blue-500 text-white px-2 py-1 rounded">
|
||||
{occupant.code}
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-2">
|
||||
<span className="text-md font-medium">
|
||||
{occupant.part_name}
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-1">
|
||||
<span className="text-sm text-gray-700">
|
||||
{t.level}: {occupant.part_level}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<div className="text-center p-4">{t.noSelections}</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default LoginOccupant;
|
||||
152
WebServices/management-frontend/src/components/auth/login.tsx
Normal file
152
WebServices/management-frontend/src/components/auth/login.tsx
Normal file
@@ -0,0 +1,152 @@
|
||||
"use client";
|
||||
import { useState, useTransition } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { loginViaAccessKeys } from "@/apicalls/login/login";
|
||||
import { z } from "zod";
|
||||
|
||||
const loginSchema = z.object({
|
||||
email: z.string().email("Invalid email address"),
|
||||
password: z.string().min(5, "Password must be at least 5 characters"),
|
||||
remember_me: z.boolean().optional().default(false),
|
||||
});
|
||||
|
||||
type LoginFormData = {
|
||||
email: string;
|
||||
password: string;
|
||||
remember_me?: boolean;
|
||||
};
|
||||
|
||||
function Login() {
|
||||
// Open transition for form login
|
||||
const [isPending, startTransition] = useTransition();
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [jsonText, setJsonText] = useState<string | null>(null);
|
||||
|
||||
const Router = useRouter();
|
||||
|
||||
const {
|
||||
register,
|
||||
formState: { errors },
|
||||
handleSubmit,
|
||||
} = useForm<LoginFormData>({
|
||||
resolver: zodResolver(loginSchema),
|
||||
});
|
||||
|
||||
const onSubmit = async (data: LoginFormData) => {
|
||||
try {
|
||||
startTransition(() => {
|
||||
try {
|
||||
loginViaAccessKeys({
|
||||
accessKey: data.email,
|
||||
password: data.password,
|
||||
rememberMe: false,
|
||||
})
|
||||
.then((result: any) => {
|
||||
const dataResponse = result?.data;
|
||||
if (dataResponse?.access_token) {
|
||||
setJsonText(JSON.stringify(dataResponse));
|
||||
setTimeout(() => {
|
||||
Router.push("/auth/select");
|
||||
}, 2000);
|
||||
}
|
||||
return dataResponse;
|
||||
})
|
||||
.catch(() => {});
|
||||
} catch (error) {}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Login error:", error);
|
||||
setError("An error occurred during login");
|
||||
}
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<div className="flex h-full min-h-[inherit] flex-col items-center justify-center gap-4">
|
||||
<div className="w-full max-w-md rounded-lg bg-white p-8 shadow-md">
|
||||
<h2 className="mb-6 text-center text-2xl font-bold text-gray-900">
|
||||
Login
|
||||
</h2>
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
|
||||
<div>
|
||||
<label
|
||||
htmlFor="email"
|
||||
className="block text-sm font-medium text-gray-700"
|
||||
>
|
||||
Email
|
||||
</label>
|
||||
<input
|
||||
{...register("email")}
|
||||
type="email"
|
||||
id="email"
|
||||
className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-indigo-500"
|
||||
/>
|
||||
{errors.email && (
|
||||
<p className="mt-1 text-sm text-red-600">
|
||||
{errors.email.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label
|
||||
htmlFor="password"
|
||||
className="block text-sm font-medium text-gray-700"
|
||||
>
|
||||
Password
|
||||
</label>
|
||||
<input
|
||||
{...register("password")}
|
||||
type="password"
|
||||
id="password"
|
||||
className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-indigo-500"
|
||||
/>
|
||||
{errors.password && (
|
||||
<p className="mt-1 text-sm text-red-600">
|
||||
{errors.password.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<div className="rounded-md bg-red-50 p-4">
|
||||
<p className="text-sm text-red-700">{error}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isPending}
|
||||
className="w-full rounded-md bg-indigo-600 px-4 py-2 text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 disabled:opacity-50"
|
||||
>
|
||||
{isPending ? "Logging in..." : "Login"}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{jsonText && (
|
||||
<div className="w-full max-w-md rounded-lg bg-white p-8 shadow-md">
|
||||
<h2 className="mb-4 text-center text-xl font-bold text-gray-900">
|
||||
Response Data
|
||||
</h2>
|
||||
<div className="space-y-2">
|
||||
{Object.entries(JSON.parse(jsonText)).map(([key, value]) => (
|
||||
<div key={key} className="flex items-start gap-2">
|
||||
<strong className="text-gray-700">{key}:</strong>
|
||||
<span className="text-gray-600">
|
||||
{typeof value === "object"
|
||||
? JSON.stringify(value)
|
||||
: value?.toString() || "N/A"}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Login;
|
||||
@@ -0,0 +1,87 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import {
|
||||
loginSelectEmployee,
|
||||
loginSelectOccupant,
|
||||
} from "@/apicalls/login/login";
|
||||
import { useRouter } from "next/navigation";
|
||||
import LoginEmployee from "./LoginEmployee";
|
||||
import LoginOccupant from "./LoginOccupant";
|
||||
import { SelectListProps, Company, BuildingMap } from "./types";
|
||||
|
||||
function SelectList({
|
||||
selectionList,
|
||||
isEmployee,
|
||||
isOccupant,
|
||||
lang = "en",
|
||||
}: SelectListProps) {
|
||||
const router = useRouter();
|
||||
|
||||
// Log the complete selectionList object and its structure
|
||||
console.log("selectionList (complete):", selectionList);
|
||||
console.log(
|
||||
"selectionList (type):",
|
||||
Array.isArray(selectionList) ? "Array" : "Object"
|
||||
);
|
||||
|
||||
if (isEmployee && Array.isArray(selectionList)) {
|
||||
console.log("Employee companies:", selectionList);
|
||||
} else if (isOccupant && !Array.isArray(selectionList)) {
|
||||
// Log each building and its occupants
|
||||
Object.entries(selectionList).forEach(([buildingKey, building]) => {
|
||||
console.log(`Building ${buildingKey}:`, building);
|
||||
console.log(`Occupants for building ${buildingKey}:`, building.occupants);
|
||||
});
|
||||
}
|
||||
|
||||
const setSelectionHandler = (uu_id: string) => {
|
||||
if (isEmployee) {
|
||||
console.log("Selected isEmployee uu_id:", uu_id);
|
||||
loginSelectEmployee({ company_uu_id: uu_id })
|
||||
.then((responseData: any) => {
|
||||
if (responseData?.status === 200 || responseData?.status === 202) {
|
||||
router.push("/dashboard");
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
});
|
||||
} else if (isOccupant) {
|
||||
console.log("Selected isOccupant uu_id:", uu_id);
|
||||
// For occupants, the uu_id is a composite of buildKey|partUuid
|
||||
loginSelectOccupant({
|
||||
build_living_space_uu_id: uu_id,
|
||||
})
|
||||
.then((responseData: any) => {
|
||||
if (responseData?.status === 200 || responseData?.status === 202) {
|
||||
router.push("/dashboard");
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{isEmployee && Array.isArray(selectionList) && (
|
||||
<LoginEmployee
|
||||
selectionList={selectionList as Company[]}
|
||||
lang={lang as "en" | "tr"}
|
||||
onSelect={setSelectionHandler}
|
||||
/>
|
||||
)}
|
||||
|
||||
{isOccupant && !Array.isArray(selectionList) && (
|
||||
<LoginOccupant
|
||||
selectionList={selectionList as BuildingMap}
|
||||
lang={lang as "en" | "tr"}
|
||||
onSelect={setSelectionHandler}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default SelectList;
|
||||
36
WebServices/management-frontend/src/components/auth/types.ts
Normal file
36
WebServices/management-frontend/src/components/auth/types.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
// TypeScript interfaces for proper type checking
|
||||
export interface Company {
|
||||
uu_id: string;
|
||||
public_name: string;
|
||||
company_type?: string;
|
||||
company_address?: any;
|
||||
duty?: string;
|
||||
}
|
||||
|
||||
export interface Occupant {
|
||||
build_living_space_uu_id: string;
|
||||
part_uu_id: string;
|
||||
part_name: string;
|
||||
part_level: number;
|
||||
occupant_uu_id: string;
|
||||
description: string;
|
||||
code: string;
|
||||
}
|
||||
|
||||
export interface Building {
|
||||
build_uu_id: string;
|
||||
build_name: string;
|
||||
build_no: string;
|
||||
occupants: Occupant[];
|
||||
}
|
||||
|
||||
export interface BuildingMap {
|
||||
[key: string]: Building;
|
||||
}
|
||||
|
||||
export interface SelectListProps {
|
||||
selectionList: Company[] | BuildingMap;
|
||||
isEmployee: boolean;
|
||||
isOccupant: boolean;
|
||||
lang?: "en" | "tr";
|
||||
}
|
||||
Reference in New Issue
Block a user