old version placed
This commit is contained in:
41
.gitignore
vendored
Normal file
41
.gitignore
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.*
|
||||
.yarn/*
|
||||
!.yarn/patches
|
||||
!.yarn/plugins
|
||||
!.yarn/releases
|
||||
!.yarn/versions
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# env files (can opt-in for committing if needed)
|
||||
.env*
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
11
README.md
11
README.md
@@ -1,3 +1,12 @@
|
||||
# wag-frontend-version-3
|
||||
|
||||
Hi. This is a server-side next-js implemented for wag frontend.
|
||||
Hi. This is a server-side next-js implemented for wag frontend.
|
||||
|
||||
Install Next js & shadcn ->
|
||||
|
||||
> npx create-next-app@latest .
|
||||
> npx shadcn@latest init
|
||||
|
||||
> npx shadcn@latest add form switch pagination table popover scroll-area calendar input button
|
||||
|
||||
--legacy-peer-deps
|
||||
|
||||
18
apicalls/accounts/account.tsx
Normal file
18
apicalls/accounts/account.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
"use server";
|
||||
import { fetchData, fetchDataWithToken } from "../api-fetcher";
|
||||
import { baseUrl, FilterList, FilterListInterface } from "../basics";
|
||||
|
||||
const accountsListEndpoint = `${baseUrl}/account/records/list`;
|
||||
|
||||
async function retrieveaccountsList(payload: FilterListInterface) {
|
||||
const feedObject = new FilterList(payload).filter();
|
||||
const tokenResponse: any = await fetchDataWithToken(
|
||||
accountsListEndpoint,
|
||||
feedObject,
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
return tokenResponse;
|
||||
}
|
||||
|
||||
export { retrieveaccountsList };
|
||||
132
apicalls/api-fetcher.tsx
Normal file
132
apicalls/api-fetcher.tsx
Normal file
@@ -0,0 +1,132 @@
|
||||
"use server";
|
||||
|
||||
import { retrieveAccessToken } from "@/apicalls/cookies/token";
|
||||
|
||||
const defaultHeaders = {
|
||||
accept: "application/json",
|
||||
"Content-type": "application/json",
|
||||
};
|
||||
|
||||
const DefaultResponse = {
|
||||
completed: false,
|
||||
error: "Hata tipi belirtilmedi",
|
||||
message: "Hata oluştu, lütfen tekrar deneyin",
|
||||
status: "500",
|
||||
data: {},
|
||||
};
|
||||
|
||||
interface HeadersObject {
|
||||
cache: string;
|
||||
method: string;
|
||||
headers: Object;
|
||||
body?: string;
|
||||
}
|
||||
|
||||
const cacheList = ["no-cache", "no-store", "force-cache", "only-if-cached"];
|
||||
|
||||
const prepareResponse = async (response: any) => {
|
||||
try {
|
||||
const responseJson = await response.json();
|
||||
const statusResponse = response?.status;
|
||||
const errorResponse = responseJson?.error || responseJson?.Error;
|
||||
const messageResponse = (responseJson?.message || "").toString();
|
||||
const completeResponse = responseJson?.completed || false;
|
||||
|
||||
const preparedResponse = {
|
||||
completed: completeResponse,
|
||||
message: messageResponse,
|
||||
status: statusResponse,
|
||||
error: errorResponse || "",
|
||||
...responseJson,
|
||||
};
|
||||
|
||||
return preparedResponse;
|
||||
} catch (error) {}
|
||||
return DefaultResponse;
|
||||
};
|
||||
|
||||
const fetchData = async (
|
||||
endpoint: string,
|
||||
payload: any,
|
||||
method: string = "POST",
|
||||
cache: boolean = false
|
||||
) => {
|
||||
let headersObject: any = {
|
||||
cache: cache ? "force-cache" : "no-cache",
|
||||
method: method,
|
||||
headers: defaultHeaders,
|
||||
};
|
||||
if (method !== "GET") {
|
||||
headersObject = {
|
||||
...headersObject,
|
||||
body: JSON.stringify(payload),
|
||||
};
|
||||
}
|
||||
console.log("headersObject", headersObject);
|
||||
try {
|
||||
const response = await fetch(endpoint, headersObject);
|
||||
return await prepareResponse(response);
|
||||
} catch (error) {}
|
||||
return DefaultResponse;
|
||||
};
|
||||
|
||||
const updateDataWithToken = async (
|
||||
endpoint: string,
|
||||
uuid: string,
|
||||
payload: any,
|
||||
method: string = "POST",
|
||||
cache: boolean = false
|
||||
) => {
|
||||
const accessToken = (await retrieveAccessToken()) || "";
|
||||
let headersObject: any = {
|
||||
cache: cache ? "force-cache" : "no-cache",
|
||||
method: method,
|
||||
headers: {
|
||||
...defaultHeaders,
|
||||
"evyos-session-key": accessToken,
|
||||
},
|
||||
};
|
||||
|
||||
if (method !== "GET") {
|
||||
headersObject = {
|
||||
...headersObject,
|
||||
body: JSON.stringify(payload.payload),
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`${endpoint}/${uuid}`, headersObject);
|
||||
return await prepareResponse(response);
|
||||
} catch (error) {}
|
||||
return DefaultResponse;
|
||||
};
|
||||
|
||||
const fetchDataWithToken = async (
|
||||
endpoint: string,
|
||||
payload: any,
|
||||
method: string = "POST",
|
||||
cache: boolean = false
|
||||
) => {
|
||||
const accessToken = (await retrieveAccessToken()) || "";
|
||||
let headersObject: any = {
|
||||
cache: cache ? "force-cache" : "no-cache",
|
||||
method: method,
|
||||
headers: {
|
||||
...defaultHeaders,
|
||||
"evyos-session-key": accessToken,
|
||||
},
|
||||
};
|
||||
if (method !== "GET") {
|
||||
headersObject = {
|
||||
...headersObject,
|
||||
body: JSON.stringify(payload),
|
||||
};
|
||||
}
|
||||
try {
|
||||
const response = await fetch(endpoint, headersObject);
|
||||
return await prepareResponse(response);
|
||||
} catch (error) {}
|
||||
return DefaultResponse;
|
||||
};
|
||||
|
||||
export { fetchData, fetchDataWithToken, updateDataWithToken };
|
||||
59
apicalls/basics.ts
Normal file
59
apicalls/basics.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
export const baseUrl = process.env.BASICURL || "";
|
||||
export const tokenSecret = process.env.TOKENSECRET || "";
|
||||
export const cookieObject: any = {
|
||||
httpOnly: true,
|
||||
path: "/",
|
||||
sameSite: "lax",
|
||||
secure: true,
|
||||
maxAge: 3600,
|
||||
};
|
||||
|
||||
interface FilterListInterface {
|
||||
page?: number | null | undefined;
|
||||
size?: number | null | undefined;
|
||||
orderField?: string | null | undefined;
|
||||
orderType?: string | null | undefined;
|
||||
includeJoins?: any[] | null | undefined;
|
||||
query?: any | null | undefined;
|
||||
}
|
||||
|
||||
class FilterList {
|
||||
page: number;
|
||||
size: number;
|
||||
orderField: string;
|
||||
orderType: string;
|
||||
includeJoins: any[];
|
||||
query: any;
|
||||
constructor({
|
||||
page = 1,
|
||||
size = 5,
|
||||
orderField = "id",
|
||||
orderType = "asc",
|
||||
includeJoins = [],
|
||||
query = {},
|
||||
}: FilterListInterface = {}) {
|
||||
this.page = page ?? 1;
|
||||
this.size = size ?? 5;
|
||||
this.orderField = orderField ?? "id";
|
||||
this.orderType = orderType ?? "asc";
|
||||
this.orderType = this.orderType.startsWith("a") ? "asc" : "desc";
|
||||
this.includeJoins = includeJoins ?? [];
|
||||
this.query = query ?? {};
|
||||
|
||||
}
|
||||
filter() {
|
||||
return {
|
||||
page: this.page,
|
||||
size: this.size,
|
||||
order_field: this.orderField,
|
||||
order_type: this.orderType,
|
||||
include_joins: this.includeJoins,
|
||||
query: this.query,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const defaultFilterList = new FilterList({});
|
||||
|
||||
export { FilterList, defaultFilterList };
|
||||
export type { FilterListInterface };
|
||||
52
apicalls/building/build.tsx
Normal file
52
apicalls/building/build.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
"use server";
|
||||
import { fetchDataWithToken, updateDataWithToken } from "../api-fetcher";
|
||||
import {
|
||||
baseUrl,
|
||||
FilterList,
|
||||
FilterListInterface,
|
||||
defaultFilterList,
|
||||
} from "../basics";
|
||||
|
||||
const buildListEndpoint = `${baseUrl}/building/build/list`;
|
||||
const buildCreateEndpoint = `${baseUrl}/building/build/create`;
|
||||
const buildUpdateEndpoint = `${baseUrl}/building/build/update`;
|
||||
|
||||
async function retrieveBuildList(payload: FilterListInterface) {
|
||||
const feedObject = new FilterList(payload).filter();
|
||||
const tokenResponse: any = await fetchDataWithToken(
|
||||
buildListEndpoint,
|
||||
feedObject,
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
return tokenResponse;
|
||||
}
|
||||
|
||||
interface BuildUpdateInterface {
|
||||
uuid: string;
|
||||
payload: any;
|
||||
}
|
||||
|
||||
async function updateBuild(payload: any) {
|
||||
const { uu_id: extractedField, ...payloadBody } = payload;
|
||||
const tokenResponse: any = await updateDataWithToken(
|
||||
buildUpdateEndpoint,
|
||||
extractedField,
|
||||
payloadBody,
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
return tokenResponse;
|
||||
}
|
||||
|
||||
async function createBuild(payload: any) {
|
||||
const tokenResponse: any = await fetchDataWithToken(
|
||||
buildCreateEndpoint,
|
||||
payload,
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
return tokenResponse;
|
||||
}
|
||||
|
||||
export { retrieveBuildList, updateBuild, createBuild };
|
||||
40
apicalls/building/livingSpace.tsx
Normal file
40
apicalls/building/livingSpace.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
"use server";
|
||||
import { fetchData, fetchDataWithToken } from "../api-fetcher";
|
||||
import { baseUrl, FilterList, FilterListInterface } from "../basics";
|
||||
|
||||
const livingSpaceListEndpoint = `${baseUrl}/building/living_space/list`;
|
||||
const livingSpaceCreateEndpoint = `${baseUrl}/building/living_space/create`;
|
||||
const livingSpaceUpdateEndpoint = `${baseUrl}/building/living_space/update`;
|
||||
|
||||
async function retrievelivingSpaceList(payload: FilterListInterface) {
|
||||
const feedObject = new FilterList(payload).filter();
|
||||
const tokenResponse: any = await fetchDataWithToken(
|
||||
livingSpaceListEndpoint,
|
||||
feedObject,
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
return tokenResponse;
|
||||
}
|
||||
|
||||
async function createLivingSpace(payload: any) {
|
||||
const tokenResponse: any = await fetchDataWithToken(
|
||||
livingSpaceCreateEndpoint,
|
||||
payload,
|
||||
"POST",
|
||||
true
|
||||
);
|
||||
return tokenResponse;
|
||||
}
|
||||
|
||||
async function updateLivingSpace(payload: any) {
|
||||
const tokenResponse: any = await fetchDataWithToken(
|
||||
livingSpaceUpdateEndpoint,
|
||||
payload,
|
||||
"POST",
|
||||
true
|
||||
);
|
||||
return tokenResponse;
|
||||
}
|
||||
|
||||
export { retrievelivingSpaceList, createLivingSpace, updateLivingSpace };
|
||||
52
apicalls/building/parts.tsx
Normal file
52
apicalls/building/parts.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
"use server";
|
||||
import { fetchDataWithToken, updateDataWithToken } from "../api-fetcher";
|
||||
import {
|
||||
baseUrl,
|
||||
FilterList,
|
||||
FilterListInterface,
|
||||
defaultFilterList,
|
||||
} from "../basics";
|
||||
|
||||
const partsListEndpoint = `${baseUrl}/building/parts/list`;
|
||||
const partsCreateEndpoint = `${baseUrl}/building/parts/create`;
|
||||
const partsUpdateEndpoint = `${baseUrl}/building/parts/update`;
|
||||
|
||||
interface BuildUpdateInterface {
|
||||
uuid: string;
|
||||
payload: any;
|
||||
}
|
||||
|
||||
async function retrievePartsList(payload: FilterListInterface) {
|
||||
const feedObject = new FilterList(payload).filter();
|
||||
const tokenResponse: any = await fetchDataWithToken(
|
||||
partsListEndpoint,
|
||||
feedObject,
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
return tokenResponse;
|
||||
}
|
||||
|
||||
async function updateParts(payload: any) {
|
||||
const { uu_id: extractedField, ...payloadBody } = payload;
|
||||
const tokenResponse: any = await updateDataWithToken(
|
||||
partsUpdateEndpoint,
|
||||
extractedField,
|
||||
payloadBody,
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
return tokenResponse;
|
||||
}
|
||||
|
||||
async function createParts(payload: any) {
|
||||
const tokenResponse: any = await fetchDataWithToken(
|
||||
partsCreateEndpoint,
|
||||
payload,
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
return tokenResponse;
|
||||
}
|
||||
|
||||
export { retrievePartsList, updateParts, createParts };
|
||||
52
apicalls/company/company.tsx
Normal file
52
apicalls/company/company.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
"use server";
|
||||
import { fetchDataWithToken, updateDataWithToken } from "../api-fetcher";
|
||||
import {
|
||||
baseUrl,
|
||||
FilterList,
|
||||
FilterListInterface,
|
||||
defaultFilterList,
|
||||
} from "../basics";
|
||||
|
||||
const CompanyListEndpoint = `${baseUrl}/company/list`;
|
||||
const CompanyCreateEndpoint = `${baseUrl}/company/create`;
|
||||
const CompanyUpdateEndpoint = `${baseUrl}/company/update`;
|
||||
|
||||
interface CompanyUpdateInterface {
|
||||
uuid: string;
|
||||
payload: any;
|
||||
}
|
||||
|
||||
async function retrieveCompanyList(payload: FilterListInterface) {
|
||||
const feedObject = new FilterList(payload).filter();
|
||||
const tokenResponse: any = await fetchDataWithToken(
|
||||
CompanyListEndpoint,
|
||||
feedObject,
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
return tokenResponse;
|
||||
}
|
||||
|
||||
async function updateCompany(payload: any) {
|
||||
const { uu_id: extractedField, ...payloadBody } = payload;
|
||||
const tokenResponse: any = await updateDataWithToken(
|
||||
CompanyUpdateEndpoint,
|
||||
extractedField,
|
||||
payloadBody,
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
return tokenResponse;
|
||||
}
|
||||
|
||||
async function createCompany(payload: any) {
|
||||
const tokenResponse: any = await fetchDataWithToken(
|
||||
CompanyCreateEndpoint,
|
||||
payload,
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
return tokenResponse;
|
||||
}
|
||||
|
||||
export { retrieveCompanyList, updateCompany, createCompany };
|
||||
121
apicalls/cookies/token.tsx
Normal file
121
apicalls/cookies/token.tsx
Normal file
@@ -0,0 +1,121 @@
|
||||
"use server";
|
||||
import { fetchDataWithToken, fetchData } from "../api-fetcher";
|
||||
import { baseUrl, tokenSecret } from "../basics";
|
||||
import { cookies } from "next/headers";
|
||||
import NextCrypto from "next-crypto";
|
||||
|
||||
const checkToken = `${baseUrl}/authentication/valid`;
|
||||
const nextCrypto = new NextCrypto(tokenSecret);
|
||||
|
||||
async function checkAccessTokenIsValid() {
|
||||
const response = await fetchDataWithToken(checkToken, {}, "GET", false);
|
||||
return response?.status === 200 ? true : false;
|
||||
}
|
||||
|
||||
async function retrieveAccessToken() {
|
||||
const cookieStore = await cookies();
|
||||
const encrpytAccessToken = cookieStore.get("accessToken")?.value || "";
|
||||
return encrpytAccessToken
|
||||
? await nextCrypto.decrypt(encrpytAccessToken)
|
||||
: null;
|
||||
}
|
||||
|
||||
async function retrieveUserType() {
|
||||
const cookieStore = await cookies();
|
||||
const encrpytaccessObject = cookieStore.get("accessObject")?.value || "{}";
|
||||
const decrpytUserType = JSON.parse(
|
||||
(await nextCrypto.decrypt(encrpytaccessObject)) || "{}"
|
||||
);
|
||||
return decrpytUserType ? decrpytUserType?.user_type : null;
|
||||
}
|
||||
|
||||
async function retrieveAccessObjects() {
|
||||
const cookieStore = await cookies();
|
||||
const encrpytAccessObject = cookieStore.get("accessObject")?.value || "";
|
||||
const decrpytAccessObject = await nextCrypto.decrypt(encrpytAccessObject);
|
||||
return decrpytAccessObject ? JSON.parse(decrpytAccessObject) : null;
|
||||
}
|
||||
|
||||
async function retrieveAvailableEvents() {
|
||||
const cookieStore = await cookies();
|
||||
const encrpytAccessObject = cookieStore.get("availableEvents")?.value || "";
|
||||
const decrpytAccessObject = await nextCrypto.decrypt(encrpytAccessObject);
|
||||
return decrpytAccessObject ? JSON.parse(decrpytAccessObject) : null;
|
||||
}
|
||||
|
||||
async function retrieveAvatarInfo() {
|
||||
const response = await fetchDataWithToken(
|
||||
`${baseUrl}/authentication/avatar`,
|
||||
{},
|
||||
"POST"
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
||||
async function retrieveUserSelection() {
|
||||
const cookieStore = await cookies();
|
||||
const encrpytUserSelection = cookieStore.get("userSelection")?.value || "";
|
||||
let decrpytUserSelection: any = await nextCrypto.decrypt(
|
||||
encrpytUserSelection
|
||||
);
|
||||
decrpytUserSelection = decrpytUserSelection
|
||||
? JSON.parse(decrpytUserSelection)
|
||||
: null;
|
||||
|
||||
const userSelection = decrpytUserSelection?.company_uu_id;
|
||||
|
||||
let objectUserSelection = {};
|
||||
|
||||
if (decrpytUserSelection?.user_type === "employee") {
|
||||
const accessObjects = (await retrieveAccessObjects()) || {};
|
||||
const companyList = accessObjects?.companies_list;
|
||||
const selectedCompany = companyList.find(
|
||||
(company: any) => company.uu_id === userSelection
|
||||
);
|
||||
if (selectedCompany) {
|
||||
objectUserSelection = {
|
||||
occupantName: `${selectedCompany?.public_name}`,
|
||||
};
|
||||
}
|
||||
} else if (decrpytUserSelection?.user_type === "occupant") {
|
||||
const buildPartUUID = userSelection?.build_part_uu_id;
|
||||
const occupantUUID = userSelection?.occupant_uu_id;
|
||||
const build_id = userSelection?.build_id;
|
||||
const accessObjects = (await retrieveAccessObjects()) || {};
|
||||
const availableOccupants = accessObjects?.available_occupants[build_id];
|
||||
const buildName = availableOccupants?.build_name;
|
||||
const buildNo = availableOccupants?.build_no;
|
||||
let selectedOccupant: any = null;
|
||||
const occupants = availableOccupants?.occupants;
|
||||
console.log("occupants", occupants);
|
||||
if (occupants) {
|
||||
selectedOccupant = occupants.find(
|
||||
(occupant: any) =>
|
||||
occupant.part_uu_id === buildPartUUID &&
|
||||
occupant.uu_id === occupantUUID
|
||||
);
|
||||
}
|
||||
if (selectedOccupant) {
|
||||
objectUserSelection = {
|
||||
buildName: `${buildName} - No:${buildNo}`,
|
||||
occupantName: `${selectedOccupant?.description} ${selectedOccupant?.part_name}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
const avatarInfo = await retrieveAvatarInfo();
|
||||
return {
|
||||
...objectUserSelection,
|
||||
lang: String(avatarInfo?.data?.lang).toLowerCase(),
|
||||
avatar: avatarInfo?.data?.avatar,
|
||||
fullName: avatarInfo?.data?.full_name,
|
||||
};
|
||||
}
|
||||
|
||||
export {
|
||||
checkAccessTokenIsValid,
|
||||
retrieveAccessToken,
|
||||
retrieveUserType,
|
||||
retrieveAccessObjects,
|
||||
retrieveAvailableEvents,
|
||||
retrieveUserSelection,
|
||||
};
|
||||
11
apicalls/dashboard/menu.tsx
Normal file
11
apicalls/dashboard/menu.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
"use server";
|
||||
import { fetchDataWithToken } from "../api-fetcher";
|
||||
import { baseUrl } from "../basics";
|
||||
|
||||
const eventList = `${baseUrl}/event/list`;
|
||||
|
||||
async function retrieveEventList() {
|
||||
return await fetchDataWithToken(eventList, {}, "GET", false);
|
||||
}
|
||||
|
||||
export { retrieveEventList };
|
||||
33
apicalls/events/available.tsx
Normal file
33
apicalls/events/available.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
"use server";
|
||||
import { fetchDataWithToken } from "../api-fetcher";
|
||||
import { cookies } from "next/headers";
|
||||
import { baseUrl, cookieObject, tokenSecret } from "../basics";
|
||||
import NextCrypto from "next-crypto";
|
||||
|
||||
const availableEventsURL = `${baseUrl}/access/endpoints/available`;
|
||||
|
||||
async function setAvailableEvents() {
|
||||
const cookieStore = await cookies();
|
||||
const nextCrypto = new NextCrypto(tokenSecret);
|
||||
|
||||
const availableResponse: any = await fetchDataWithToken(
|
||||
availableEventsURL,
|
||||
{},
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
|
||||
if (availableResponse.status === 200) {
|
||||
const availableEventData = Array.from(availableResponse?.result) || [];
|
||||
const availableEvents = await nextCrypto.encrypt(
|
||||
JSON.stringify({ availableEvents: availableEventData })
|
||||
);
|
||||
cookieStore.set({
|
||||
name: "availableEvents",
|
||||
value: availableEvents,
|
||||
...cookieObject,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export { setAvailableEvents };
|
||||
151
apicalls/login/login.tsx
Normal file
151
apicalls/login/login.tsx
Normal file
@@ -0,0 +1,151 @@
|
||||
"use server";
|
||||
import { fetchData, fetchDataWithToken } from "../api-fetcher";
|
||||
import { cookies } from "next/headers";
|
||||
import { baseUrl, cookieObject, tokenSecret } from "../basics";
|
||||
import NextCrypto from "next-crypto";
|
||||
import { setAvailableEvents } from "../events/available";
|
||||
|
||||
const loginEndpoint = `${baseUrl}/authentication/login`;
|
||||
const loginSelectEndpoint = `${baseUrl}/authentication/select`;
|
||||
|
||||
interface LoginViaAccessKeys {
|
||||
domain: string;
|
||||
accessKey: string;
|
||||
password: string;
|
||||
rememberMe: boolean;
|
||||
}
|
||||
|
||||
interface LoginSelectEmployee {
|
||||
company_uu_id: string;
|
||||
}
|
||||
|
||||
interface LoginSelectOccupant {
|
||||
selectedBuilding: any;
|
||||
build_part_uu_id: string;
|
||||
occupant_uu_id: string;
|
||||
}
|
||||
|
||||
async function loginViaAccessKeys(payload: LoginViaAccessKeys) {
|
||||
const cookieStore = await cookies();
|
||||
const nextCrypto = new NextCrypto(tokenSecret);
|
||||
|
||||
const tokenResponse: any = await fetchData(
|
||||
loginEndpoint,
|
||||
{
|
||||
domain: payload.domain,
|
||||
access_key: payload.accessKey,
|
||||
password: payload.password,
|
||||
remember_me: payload.rememberMe,
|
||||
},
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
|
||||
if (tokenResponse.status === 200) {
|
||||
const accessToken = await nextCrypto.encrypt(tokenResponse.access_token);
|
||||
const accessObject = await nextCrypto.encrypt(
|
||||
JSON.stringify(tokenResponse.access_object)
|
||||
);
|
||||
const userProfile = await nextCrypto.encrypt(
|
||||
JSON.stringify(tokenResponse.user)
|
||||
);
|
||||
const refreshToken = await nextCrypto.encrypt(tokenResponse.refresh_token);
|
||||
|
||||
// const userType = await nextCrypto.encrypt(responseData.user_type);
|
||||
// cookieStore.set({
|
||||
// name: "refreshToken",
|
||||
// value: refreshToken,
|
||||
// httpOnly: true,
|
||||
// path: "/",
|
||||
// });
|
||||
|
||||
cookieStore.set({
|
||||
name: "accessToken",
|
||||
value: accessToken,
|
||||
...cookieObject,
|
||||
});
|
||||
|
||||
cookieStore.set({
|
||||
name: "accessObject",
|
||||
value: accessObject,
|
||||
...cookieObject,
|
||||
});
|
||||
cookieStore.set({
|
||||
name: "userProfile",
|
||||
value: JSON.stringify(userProfile),
|
||||
...cookieObject,
|
||||
});
|
||||
// cookieStore.set({
|
||||
// name: "userType",
|
||||
// value: userType,
|
||||
// ...cookieObject,
|
||||
// });
|
||||
}
|
||||
return tokenResponse;
|
||||
}
|
||||
|
||||
async function loginSelectEmployee(payload: LoginSelectEmployee) {
|
||||
const cookieStore = await cookies();
|
||||
const nextCrypto = new NextCrypto(tokenSecret);
|
||||
|
||||
const selectResponse: any = await fetchDataWithToken(
|
||||
loginSelectEndpoint,
|
||||
{
|
||||
company_uu_id: payload.company_uu_id,
|
||||
},
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
if (selectResponse.status === 200) {
|
||||
const usersSelection = await nextCrypto.encrypt(
|
||||
JSON.stringify({
|
||||
company_uu_id: payload.company_uu_id,
|
||||
user_type: "employee",
|
||||
})
|
||||
);
|
||||
cookieStore.set({
|
||||
name: "userSelection",
|
||||
value: usersSelection,
|
||||
...cookieObject,
|
||||
});
|
||||
await setAvailableEvents();
|
||||
}
|
||||
return selectResponse;
|
||||
}
|
||||
|
||||
async function loginSelectOccupant(payload: LoginSelectOccupant) {
|
||||
const selectedBuilding = payload.selectedBuilding;
|
||||
const cookieStore = await cookies();
|
||||
const nextCrypto = new NextCrypto(tokenSecret);
|
||||
const selectResponse: any = await fetchDataWithToken(
|
||||
loginSelectEndpoint,
|
||||
{
|
||||
build_part_uu_id: payload.build_part_uu_id,
|
||||
occupant_uu_id: payload.occupant_uu_id,
|
||||
},
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
|
||||
if (selectResponse.status === 200) {
|
||||
const usersSelection = await nextCrypto.encrypt(
|
||||
JSON.stringify({
|
||||
company_uu_id: {
|
||||
build_part_uu_id: payload.build_part_uu_id,
|
||||
occupant_uu_id: payload.occupant_uu_id,
|
||||
build_id: selectedBuilding,
|
||||
},
|
||||
user_type: "occupant",
|
||||
})
|
||||
);
|
||||
cookieStore.set({
|
||||
name: "userSelection",
|
||||
value: usersSelection,
|
||||
...cookieObject,
|
||||
});
|
||||
await setAvailableEvents();
|
||||
}
|
||||
return selectResponse;
|
||||
}
|
||||
|
||||
export { loginViaAccessKeys, loginSelectEmployee, loginSelectOccupant };
|
||||
54
apicalls/login/logout.tsx
Normal file
54
apicalls/login/logout.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
"use server";
|
||||
import { fetchDataWithToken } from "../api-fetcher";
|
||||
import { cookies } from "next/headers";
|
||||
import { baseUrl } from "../basics";
|
||||
|
||||
const logOutEndpoint = `${baseUrl}/authentication/logout`;
|
||||
const logOutAllEndpoint = `${baseUrl}/authentication/disconnect`;
|
||||
|
||||
interface LoginOutUser {
|
||||
domain: string;
|
||||
}
|
||||
|
||||
async function logoutActiveSession(payload: LoginOutUser) {
|
||||
const cookieStore = await cookies();
|
||||
cookieStore.delete("accessToken");
|
||||
cookieStore.delete("accessObject");
|
||||
cookieStore.delete("userProfile");
|
||||
cookieStore.delete("userSelection");
|
||||
|
||||
const tokenResponse: any = await fetchDataWithToken(
|
||||
logOutEndpoint,
|
||||
{
|
||||
domain: payload.domain,
|
||||
},
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
if (tokenResponse.status === 200) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async function logoutAllSessions(payload: LoginOutUser) {
|
||||
const cookieStore = await cookies();
|
||||
cookieStore.delete("accessToken");
|
||||
cookieStore.delete("accessObject");
|
||||
cookieStore.delete("userProfile");
|
||||
cookieStore.delete("userSelection");
|
||||
const tokenResponse: any = await fetchDataWithToken(
|
||||
logOutAllEndpoint,
|
||||
{
|
||||
domain: payload.domain,
|
||||
},
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
if (tokenResponse.status === 200) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export { logoutActiveSession, logoutAllSessions };
|
||||
69
apicalls/login/password.tsx
Normal file
69
apicalls/login/password.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
"use server";
|
||||
import { fetchData, fetchDataWithToken } from "../api-fetcher";
|
||||
import { baseUrl } from "../basics";
|
||||
|
||||
const createPasswordEndpoint = `${baseUrl}/authentication/create_password`;
|
||||
const changePasswordEndpoint = `${baseUrl}/authentication/change_password`;
|
||||
const forgotPasswordEndpoint = `${baseUrl}/authentication/reset_password`;
|
||||
|
||||
interface createPasswordViaToken {
|
||||
token: string;
|
||||
password: string;
|
||||
rePassword: string;
|
||||
}
|
||||
|
||||
interface changePasswordViaToken {
|
||||
oldPassword: string;
|
||||
newPassword: string;
|
||||
}
|
||||
|
||||
interface sendForgotPasswordEmail {
|
||||
domain: string;
|
||||
accessKey: string;
|
||||
}
|
||||
|
||||
async function create_password_via_token(payload: createPasswordViaToken) {
|
||||
const createPasswordResponse: any = await fetchData(
|
||||
createPasswordEndpoint,
|
||||
{
|
||||
password_token: payload.token,
|
||||
password: payload.password,
|
||||
re_password: payload.rePassword,
|
||||
},
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
return createPasswordResponse;
|
||||
}
|
||||
|
||||
async function change_password_via_token(payload: changePasswordViaToken) {
|
||||
const changePasswordResponse: any = await fetchDataWithToken(
|
||||
changePasswordEndpoint,
|
||||
{
|
||||
old_password: payload.oldPassword,
|
||||
new_password: payload.newPassword,
|
||||
},
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
return changePasswordResponse;
|
||||
}
|
||||
|
||||
async function send_forgot_password_email(payload: sendForgotPasswordEmail) {
|
||||
const response: any = await fetchData(
|
||||
forgotPasswordEndpoint,
|
||||
{
|
||||
domain: payload.domain,
|
||||
access_key: payload.accessKey,
|
||||
},
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
||||
export {
|
||||
create_password_via_token,
|
||||
change_password_via_token,
|
||||
send_forgot_password_email,
|
||||
};
|
||||
52
apicalls/people/people.tsx
Normal file
52
apicalls/people/people.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
"use server";
|
||||
import { fetchDataWithToken, updateDataWithToken } from "../api-fetcher";
|
||||
import {
|
||||
baseUrl,
|
||||
FilterList,
|
||||
FilterListInterface,
|
||||
defaultFilterList,
|
||||
} from "../basics";
|
||||
|
||||
const peopleListEndpoint = `${baseUrl}/people/list`;
|
||||
const peopleCreateEndpoint = `${baseUrl}/people/create`;
|
||||
const peopleUpdateEndpoint = `${baseUrl}/people/update`;
|
||||
|
||||
interface PeopleUpdateInterface {
|
||||
uuid: string;
|
||||
payload: any;
|
||||
}
|
||||
|
||||
async function retrievePeopleList(payload: FilterListInterface) {
|
||||
const feedObject = new FilterList(payload).filter();
|
||||
const tokenResponse: any = await fetchDataWithToken(
|
||||
peopleListEndpoint,
|
||||
feedObject,
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
return tokenResponse;
|
||||
}
|
||||
|
||||
async function updatePeople(payload: any) {
|
||||
const { uu_id: extractedField, ...payloadBody } = payload;
|
||||
const tokenResponse: any = await updateDataWithToken(
|
||||
peopleUpdateEndpoint,
|
||||
extractedField,
|
||||
payloadBody,
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
return tokenResponse;
|
||||
}
|
||||
|
||||
async function createPeople(payload: any) {
|
||||
const tokenResponse: any = await fetchDataWithToken(
|
||||
peopleCreateEndpoint,
|
||||
payload,
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
return tokenResponse;
|
||||
}
|
||||
|
||||
export { retrievePeopleList, updatePeople, createPeople };
|
||||
43
apicalls/validations/validationProcesser.ts
Normal file
43
apicalls/validations/validationProcesser.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { console } from "inspector";
|
||||
|
||||
interface ValidationInterface {
|
||||
required: string[];
|
||||
title: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
interface HeadersAndValidationsInterface {
|
||||
headers: Object;
|
||||
validation: ValidationInterface;
|
||||
language: string;
|
||||
properties: Object;
|
||||
}
|
||||
|
||||
class HeadersAndValidations {
|
||||
headers: Object;
|
||||
validation: ValidationInterface;
|
||||
language: string;
|
||||
validated: any = {};
|
||||
|
||||
constructor({
|
||||
headers,
|
||||
validation,
|
||||
language,
|
||||
}: HeadersAndValidationsInterface) {
|
||||
this.headers = headers;
|
||||
this.validation = validation;
|
||||
this.language = language;
|
||||
this.parseProcesser();
|
||||
}
|
||||
|
||||
parseProcesser() {
|
||||
Object.entries(this.validation).map(([key, value]) => {
|
||||
this.validated[key] = {
|
||||
required: !value.required,
|
||||
fieldType: value?.type,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export { HeadersAndValidations };
|
||||
67
apicalls/validations/validations.tsx
Normal file
67
apicalls/validations/validations.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
"use server";
|
||||
import { fetchData, fetchDataWithToken } from "@/apicalls/api-fetcher";
|
||||
import { baseUrl, cookieObject, tokenSecret } from "@/apicalls/basics";
|
||||
|
||||
import { HeadersAndValidations } from "@/apicalls/validations/validationProcesser";
|
||||
|
||||
const headersAndValidationEndpoint = `${baseUrl}/validations/endpoint`;
|
||||
|
||||
interface EndpointInterface {
|
||||
endpoint: string;
|
||||
}
|
||||
|
||||
async function retrieveHeadersEndpoint({ endpoint }: EndpointInterface) {
|
||||
const selectResponse: any = await fetchDataWithToken(
|
||||
headersAndValidationEndpoint,
|
||||
{
|
||||
endpoint: endpoint,
|
||||
},
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
if (selectResponse.status === 200) {
|
||||
return {
|
||||
status: selectResponse.status,
|
||||
headers: selectResponse?.headers,
|
||||
message: selectResponse.message,
|
||||
};
|
||||
}
|
||||
return {
|
||||
status: selectResponse.status,
|
||||
headers: {},
|
||||
message: selectResponse.message,
|
||||
};
|
||||
}
|
||||
|
||||
async function retrieveHeadersAndValidationByEndpoint({
|
||||
endpoint,
|
||||
}: EndpointInterface) {
|
||||
console.log("endpoint", endpoint);
|
||||
const selectResponse: any = await fetchDataWithToken(
|
||||
headersAndValidationEndpoint,
|
||||
{
|
||||
endpoint: endpoint,
|
||||
},
|
||||
"POST",
|
||||
false
|
||||
);
|
||||
if (selectResponse.status === 200) {
|
||||
const responseParsed = new HeadersAndValidations(selectResponse);
|
||||
return {
|
||||
status: selectResponse.status,
|
||||
headers: responseParsed.headers,
|
||||
validated: responseParsed.validated,
|
||||
language: responseParsed.language,
|
||||
message: selectResponse.message,
|
||||
};
|
||||
}
|
||||
return {
|
||||
status: selectResponse.status,
|
||||
message: selectResponse.message,
|
||||
|
||||
headers: null,
|
||||
validated: null,
|
||||
};
|
||||
}
|
||||
|
||||
export { retrieveHeadersAndValidationByEndpoint, retrieveHeadersEndpoint };
|
||||
9
apimaps/accesible/pageInfo.ts
Normal file
9
apimaps/accesible/pageInfo.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
const AccesibleAllEndpoints = [
|
||||
"/event/list",
|
||||
"/bind/services/occupant",
|
||||
"/bind/services/employee",
|
||||
];
|
||||
|
||||
const AccesibleSelfEndpoints = ["/event/list"];
|
||||
|
||||
export { AccesibleAllEndpoints, AccesibleSelfEndpoints };
|
||||
18
apimaps/accesible/subCategories.tsx
Normal file
18
apimaps/accesible/subCategories.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
const AccesibleCategories = [
|
||||
{
|
||||
title: {
|
||||
tr: "Yetkiler",
|
||||
en: "Permissions",
|
||||
},
|
||||
icon: "PackageCheck",
|
||||
component: null,
|
||||
selfEndpoints: [
|
||||
"/event/list",
|
||||
"/bind/services/occupant",
|
||||
"/bind/services/employee",
|
||||
],
|
||||
allEndpoints: [],
|
||||
subCategories: [],
|
||||
},
|
||||
];
|
||||
export { AccesibleCategories };
|
||||
0
apimaps/accounts/iconSet.tsx
Normal file
0
apimaps/accounts/iconSet.tsx
Normal file
24
apimaps/accounts/pageInfo.ts
Normal file
24
apimaps/accounts/pageInfo.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
const AccountAllEndpoints = ["/account/records/list"];
|
||||
|
||||
const AccountPageInfo = {
|
||||
tr: [
|
||||
{
|
||||
title: "Hesaplar",
|
||||
endpoint: "/account/records/list",
|
||||
description: "Hesaplarınızı listeyebilirsiniz",
|
||||
component: "Table",
|
||||
icon: null,
|
||||
},
|
||||
],
|
||||
en: [
|
||||
{
|
||||
title: "Accounts",
|
||||
endpoint: "/account/records/list",
|
||||
description: "You can list your accounts",
|
||||
component: "Table",
|
||||
icon: null,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export { AccountAllEndpoints, AccountPageInfo };
|
||||
15
apimaps/accounts/subCategories.tsx
Normal file
15
apimaps/accounts/subCategories.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
const AccountSubCategories = [
|
||||
{
|
||||
title: {
|
||||
tr: "Bakiye Sorgulama",
|
||||
en: "Balance Inquiry",
|
||||
},
|
||||
icon: "LucideLandmark",
|
||||
component: null,
|
||||
selfEndpoints: ["/account/records/list"],
|
||||
allEndpoints: [],
|
||||
subCategories: [],
|
||||
},
|
||||
];
|
||||
|
||||
export { AccountSubCategories };
|
||||
0
apimaps/address/iconSet.tsx
Normal file
0
apimaps/address/iconSet.tsx
Normal file
0
apimaps/building/iconSet.tsx
Normal file
0
apimaps/building/iconSet.tsx
Normal file
1
apimaps/building/page.tsx
Normal file
1
apimaps/building/page.tsx
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
71
apimaps/building/pageInfo.ts
Normal file
71
apimaps/building/pageInfo.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
const BuildPageInfo = {
|
||||
tr: [
|
||||
{
|
||||
title: "Bina Listesi",
|
||||
icon: null,
|
||||
description: "Bina listeyebilirsiniz",
|
||||
endpoint: "/building/build/list",
|
||||
component: "Table",
|
||||
},
|
||||
{
|
||||
title: "Bina Ekle",
|
||||
icon: "BadgePlus",
|
||||
description: "Bina oluşturma sayfasına hoş geldiniz",
|
||||
endpoint: "/building/build/create",
|
||||
component: "AddCreate2Table",
|
||||
},
|
||||
{
|
||||
title: null,
|
||||
icon: "Pencil",
|
||||
description: "Bina güncelleme sayfasına hoş geldiniz",
|
||||
endpoint: "/building/build/update/{build_uu_id}",
|
||||
component: "AddUpdate2Table",
|
||||
},
|
||||
],
|
||||
en: [
|
||||
{
|
||||
title: "Building List",
|
||||
icon: null,
|
||||
description: "Welcome to the building update page",
|
||||
endpoint: "/building/build/list",
|
||||
component: "Table",
|
||||
},
|
||||
{
|
||||
title: "Create Building",
|
||||
icon: "BadgePlus",
|
||||
description: "Welcome to the building creation page",
|
||||
endpoint: "/building/build/create",
|
||||
component: "AddCreate2Table",
|
||||
},
|
||||
{
|
||||
title: "Update Building",
|
||||
icon: "Pencil",
|
||||
description: "Welcome to the building update page",
|
||||
endpoint: "/building/build/update/{build_uu_id}",
|
||||
component: "AddUpdate2Table",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const BuildAllEndpoints = [
|
||||
"/building/build/list",
|
||||
"/building/build/create",
|
||||
"/building/build/update/{build_uu_id}",
|
||||
"/building/parts/list",
|
||||
"/building/parts/create",
|
||||
"/building/parts/update/{build_uu_id}",
|
||||
"/building/area/list",
|
||||
"/building/area/create",
|
||||
"/building/area/update/{build_uu_id}",
|
||||
"/building/living_space/list",
|
||||
"/building/living_space/create",
|
||||
"/building/living_space/update/{build_uu_id}",
|
||||
];
|
||||
|
||||
const BuildSelfEndpoints = [
|
||||
"/building/build/list",
|
||||
"/building/build/create",
|
||||
"/building/build/update/{build_uu_id}",
|
||||
];
|
||||
|
||||
export { BuildPageInfo, BuildSelfEndpoints, BuildAllEndpoints };
|
||||
45
apimaps/building/subCategories.tsx
Normal file
45
apimaps/building/subCategories.tsx
Normal file
@@ -0,0 +1,45 @@
|
||||
import { LivingSpaceInfo } from "../livingSpace/pageInfo";
|
||||
import { PartsPageInfo } from "../parts/pageInfo";
|
||||
|
||||
const BuildCategories = [
|
||||
{
|
||||
title: {
|
||||
tr: "Daireler",
|
||||
en: "Flats",
|
||||
},
|
||||
icon: "DoorOpen",
|
||||
component: "PartsPage",
|
||||
pageInfo: PartsPageInfo,
|
||||
allEndpoints: [],
|
||||
subCategories: [],
|
||||
},
|
||||
{
|
||||
title: {
|
||||
tr: "Kullanılabilir Alanlar",
|
||||
en: "Building Areas",
|
||||
},
|
||||
icon: "TreePine",
|
||||
component: null,
|
||||
selfEndpoints: [
|
||||
"/building/area/list",
|
||||
"/building/area/create",
|
||||
"/building/area/update/{build_uu_id}",
|
||||
],
|
||||
pageInfo: null,
|
||||
allEndpoints: [],
|
||||
subCategories: [],
|
||||
},
|
||||
{
|
||||
title: {
|
||||
tr: "Yaşayan Kişiler",
|
||||
en: "Living People",
|
||||
},
|
||||
icon: "UsersRound",
|
||||
component: "LivingSpacePage",
|
||||
pageInfo: LivingSpaceInfo,
|
||||
allEndpoints: [],
|
||||
subCategories: [],
|
||||
},
|
||||
];
|
||||
|
||||
export { BuildCategories };
|
||||
0
apimaps/company/iconSet.tsx
Normal file
0
apimaps/company/iconSet.tsx
Normal file
76
apimaps/company/pageInfo.ts
Normal file
76
apimaps/company/pageInfo.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
const CompanySelfEndpoints = [
|
||||
"/company/list",
|
||||
"/company/create",
|
||||
"/company/update/{company_uu_id}",
|
||||
];
|
||||
|
||||
const CompanyAllEndpoints = [
|
||||
"/company/list",
|
||||
"/company/create",
|
||||
"/company/update/{company_uu_id}",
|
||||
"/department/list",
|
||||
"/department/create",
|
||||
"/department/update/{department_uu_id}",
|
||||
"/duties/list",
|
||||
"/duties/create",
|
||||
"/duties/update",
|
||||
"/employee/list",
|
||||
"/employee/create",
|
||||
"/employee/update/{employee_uu_id}",
|
||||
"/employee/employ",
|
||||
"/employee/fire",
|
||||
"/staff/list",
|
||||
"/staff/create",
|
||||
"/staff/update/{staff_uu_id}",
|
||||
];
|
||||
|
||||
const CompanyPageInfo = {
|
||||
tr: [
|
||||
{
|
||||
title: "Şirket Listesi",
|
||||
icon: null,
|
||||
description: "Şirketleri listeyebilirsiniz",
|
||||
endpoint: "/company/list",
|
||||
component: "Table",
|
||||
},
|
||||
{
|
||||
title: "Şirket Ekle",
|
||||
icon: "BadgePlus",
|
||||
description: "Şirket oluşturma sayfasına hoş geldiniz",
|
||||
endpoint: "/company/create",
|
||||
component: "AddCreate2Table",
|
||||
},
|
||||
{
|
||||
title: null,
|
||||
icon: "Pencil",
|
||||
description: "Şirket güncelleme sayfasına hoş geldiniz",
|
||||
endpoint: "/company/update/{company_uu_id}",
|
||||
component: "AddUpdate2Table",
|
||||
},
|
||||
],
|
||||
en: [
|
||||
{
|
||||
title: "Company List",
|
||||
icon: null,
|
||||
description: "Welcome to the company update page",
|
||||
endpoint: "/company/list",
|
||||
component: "Table",
|
||||
},
|
||||
{
|
||||
title: "Create Company",
|
||||
icon: "BadgePlus",
|
||||
description: "Welcome to the company creation page",
|
||||
endpoint: "/company/create",
|
||||
component: "AddCreate2Table",
|
||||
},
|
||||
{
|
||||
title: "Update Company",
|
||||
icon: "Pencil",
|
||||
description: "Welcome to the company update page",
|
||||
endpoint: "/company/update/{company_uu_id}",
|
||||
component: "AddUpdate2Table",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export { CompanyAllEndpoints, CompanySelfEndpoints, CompanyPageInfo };
|
||||
62
apimaps/company/subCategories.tsx
Normal file
62
apimaps/company/subCategories.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
const CompanyCategories = [
|
||||
{
|
||||
title: {
|
||||
tr: "Departmanlar",
|
||||
en: "Departments",
|
||||
},
|
||||
icon: "FolderOpenDot",
|
||||
component: null,
|
||||
selfEndpoints: [
|
||||
"/department/list",
|
||||
"/department/create",
|
||||
"/department/update/{department_uu_id}",
|
||||
],
|
||||
allEndpoints: [],
|
||||
subCategories: [],
|
||||
},
|
||||
{
|
||||
title: {
|
||||
tr: "Görevler",
|
||||
en: "Duties",
|
||||
},
|
||||
icon: "BriefcaseMedical",
|
||||
component: null,
|
||||
selfEndpoints: ["/duties/list", "/duties/create", "/duties/update"],
|
||||
allEndpoints: [],
|
||||
subCategories: [],
|
||||
},
|
||||
{
|
||||
title: {
|
||||
tr: "Çalışanlar",
|
||||
en: "Employees",
|
||||
},
|
||||
icon: "Pickaxe",
|
||||
component: null,
|
||||
selfEndpoints: [
|
||||
"/employee/list",
|
||||
"/employee/create",
|
||||
"/employee/update/{employee_uu_id}",
|
||||
"/employee/employ",
|
||||
"/employee/fire",
|
||||
],
|
||||
allEndpoints: [],
|
||||
subCategories: [],
|
||||
},
|
||||
{
|
||||
title: {
|
||||
tr: "Personel",
|
||||
en: "Staff",
|
||||
},
|
||||
icon: "BicepsFlexed",
|
||||
component: null,
|
||||
selfEndpoints: [
|
||||
"/staff/list",
|
||||
"/staff/create",
|
||||
"/staff/update/{staff_uu_id}",
|
||||
],
|
||||
allEndpoints: [],
|
||||
subCategories: [],
|
||||
},
|
||||
];
|
||||
|
||||
export { CompanyCategories };
|
||||
0
apimaps/decisionBook/iconSet.tsx
Normal file
0
apimaps/decisionBook/iconSet.tsx
Normal file
101
apimaps/decisionBook/pageInfo.ts
Normal file
101
apimaps/decisionBook/pageInfo.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
const DecisionBookAllEndpoints = [
|
||||
"/build/decision_book/list",
|
||||
"/build/decision_book/create",
|
||||
"/build/decision_book/update/{decision_book_uu_id}",
|
||||
"/build/decision_book/approval",
|
||||
"/build/decision_book/items/list",
|
||||
"/build/decision_book/items/create",
|
||||
"/build/decision_book/items/update/{decision_book_item_uu_id}",
|
||||
"/build/decision_book/people/list",
|
||||
"/build/decision_book/people/add",
|
||||
"/build/decision_book/people/remove",
|
||||
"/build/decision_book/project/list",
|
||||
"/build/decision_book/project/create",
|
||||
"/build/decision_book/project/update/{project_uu_id}",
|
||||
"/build/decision_book/project/approval",
|
||||
"/build/decision_book/project/items/list",
|
||||
"/build/decision_book/project/items/create",
|
||||
"/build/decision_book/project/items/update/{project_item_uu_id}",
|
||||
"/build/decision_book/project/people/list",
|
||||
"/build/decision_book/project/people/create",
|
||||
"/build/decision_book/project/people/update/{project_people_uu_id}",
|
||||
];
|
||||
const DecisionBookSelfEndpoints = [
|
||||
"/build/decision_book/list",
|
||||
"/build/decision_book/create",
|
||||
"/build/decision_book/update/{decision_book_uu_id}",
|
||||
];
|
||||
|
||||
const DecisionBookItemAllEndpoints = [
|
||||
"/build/decision_book/items/list",
|
||||
"/build/decision_book/items/create",
|
||||
"/build/decision_book/items/update/{decision_book_item_uu_id}",
|
||||
"/build/decision_book/people/list",
|
||||
"/build/decision_book/people/add",
|
||||
"/build/decision_book/people/remove",
|
||||
];
|
||||
const ProjectBookItemsAllEndpoints = [
|
||||
"/build/decision_book/project/items/list",
|
||||
"/build/decision_book/project/items/create",
|
||||
"/build/decision_book/project/items/update/{project_item_uu_id}",
|
||||
"/build/decision_book/project/people/list",
|
||||
"/build/decision_book/project/people/create",
|
||||
"/build/decision_book/project/people/update/{project_people_uu_id}",
|
||||
];
|
||||
|
||||
const DecisionBookPageInfo = {
|
||||
tr: [
|
||||
{
|
||||
title: "Karar Defteri Listesi",
|
||||
icon: null,
|
||||
description: "Karar Defteri listeyebilirsiniz",
|
||||
endpoint: "/decision_book/list",
|
||||
component: "Table",
|
||||
},
|
||||
{
|
||||
title: "Karar Defteri Ekle",
|
||||
icon: "BadgePlus",
|
||||
description: "Karar Defteri oluşturma sayfasına hoş geldiniz",
|
||||
endpoint: "/decision_book/create",
|
||||
component: "AddCreate2Table",
|
||||
},
|
||||
{
|
||||
title: "Karar Defteri Güncelle",
|
||||
icon: "Pencil",
|
||||
description: "Karar Defteri güncelleme sayfasına hoş geldiniz",
|
||||
endpoint: "/decision_book/update/{company_uu_id}",
|
||||
component: "AddUpdate2Table",
|
||||
},
|
||||
],
|
||||
en: [
|
||||
{
|
||||
title: "Decision Book List",
|
||||
icon: null,
|
||||
description: "Welcome to the decision book update page",
|
||||
endpoint: "/decision_book/list",
|
||||
component: "Table",
|
||||
},
|
||||
{
|
||||
title: "Create Decision Book",
|
||||
icon: "BadgePlus",
|
||||
description: "Welcome to the decision book creation page",
|
||||
endpoint: "/decision_book/create",
|
||||
component: "AddCreate2Table",
|
||||
},
|
||||
{
|
||||
title: "Update Decision Book",
|
||||
icon: "Pencil",
|
||||
description: "Welcome to the decision book update page",
|
||||
endpoint: "/decision_book/update/{company_uu_id}",
|
||||
component: "AddUpdate2Table",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export {
|
||||
DecisionBookAllEndpoints,
|
||||
DecisionBookSelfEndpoints,
|
||||
DecisionBookItemAllEndpoints,
|
||||
ProjectBookItemsAllEndpoints,
|
||||
DecisionBookPageInfo,
|
||||
};
|
||||
106
apimaps/decisionBook/subCategories.tsx
Normal file
106
apimaps/decisionBook/subCategories.tsx
Normal file
@@ -0,0 +1,106 @@
|
||||
import {
|
||||
DecisionBookAllEndpoints,
|
||||
DecisionBookItemAllEndpoints,
|
||||
ProjectBookItemsAllEndpoints,
|
||||
} from "./pageInfo";
|
||||
|
||||
const DecisionBookCategories = [
|
||||
{
|
||||
title: {
|
||||
tr: "Kararlar",
|
||||
en: "Decisions",
|
||||
},
|
||||
icon: "Stamp",
|
||||
component: null,
|
||||
selfEndpoints: [
|
||||
"/build/decision_book/items/list",
|
||||
"/build/decision_book/items/create",
|
||||
"/build/decision_book/items/update/{decision_book_item_uu_id}",
|
||||
],
|
||||
allEndpoints: [],
|
||||
subCategories: [],
|
||||
},
|
||||
{
|
||||
title: {
|
||||
tr: "Karar Defteri Kişiler",
|
||||
en: "Decision Book People",
|
||||
},
|
||||
icon: "FolderCheck",
|
||||
component: null,
|
||||
selfEndpoints: [
|
||||
"/build/decision_book/people/list",
|
||||
"/build/decision_book/people/add",
|
||||
"/build/decision_book/people/remove",
|
||||
],
|
||||
allEndpoints: [],
|
||||
subCategories: [],
|
||||
},
|
||||
];
|
||||
|
||||
const ProjectBookItemsCategories = [
|
||||
{
|
||||
title: {
|
||||
tr: "Proje Dosya İşlemleri",
|
||||
en: "Project File Operations",
|
||||
},
|
||||
icon: "FolderKey",
|
||||
component: null,
|
||||
selfEndpoints: [
|
||||
"/build/decision_book/project/items/list",
|
||||
"/build/decision_book/project/items/create",
|
||||
"/build/decision_book/project/items/update/{project_item_uu_id}",
|
||||
],
|
||||
allEndpoints: [],
|
||||
subCategories: [],
|
||||
},
|
||||
{
|
||||
title: {
|
||||
tr: "Proje Dosya Kişiler",
|
||||
en: "Project File People",
|
||||
},
|
||||
icon: "FolderCog",
|
||||
component: null,
|
||||
selfEndpoints: [
|
||||
"/build/decision_book/project/people/list",
|
||||
"/build/decision_book/project/people/create",
|
||||
"/build/decision_book/project/people/update/{project_people_uu_id}",
|
||||
],
|
||||
allEndpoints: [],
|
||||
subCategories: [],
|
||||
},
|
||||
];
|
||||
|
||||
const DecisionBookSubCategories = [
|
||||
{
|
||||
title: {
|
||||
tr: "Kararlar",
|
||||
en: "Decisions",
|
||||
},
|
||||
icon: "ScrollText",
|
||||
component: "",
|
||||
selfEndpoints: [
|
||||
"/build/decision_book/items/list",
|
||||
"/build/decision_book/items/create",
|
||||
"/build/decision_book/items/update/{decision_book_item_uu_id}",
|
||||
],
|
||||
allEndpoints: DecisionBookItemAllEndpoints,
|
||||
subCategories: DecisionBookCategories,
|
||||
},
|
||||
{
|
||||
title: {
|
||||
tr: "Proje Dosyaları",
|
||||
en: "Project Files",
|
||||
},
|
||||
icon: "Projector",
|
||||
component: "",
|
||||
selfEndpoints: [
|
||||
"/build/decision_book/project/list",
|
||||
"/build/decision_book/project/create",
|
||||
"/build/decision_book/project/update/{project_uu_id}",
|
||||
],
|
||||
allEndpoints: ProjectBookItemsAllEndpoints,
|
||||
subCategories: ProjectBookItemsCategories,
|
||||
},
|
||||
];
|
||||
|
||||
export { DecisionBookSubCategories };
|
||||
0
apimaps/identity/iconSet.tsx
Normal file
0
apimaps/identity/iconSet.tsx
Normal file
22
apimaps/identity/pageInfo.ts
Normal file
22
apimaps/identity/pageInfo.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
const IdentityAllEndpoints = [
|
||||
"/users/list",
|
||||
"/users/create",
|
||||
"/users/update/{user_uu_id}",
|
||||
"/people/list",
|
||||
"/people/create",
|
||||
"/people/update/{people_uu_id}",
|
||||
];
|
||||
|
||||
const IdentitySelfEndpoints = ["/users/list"];
|
||||
|
||||
const AddressAllEndpoints = [
|
||||
"/address/list",
|
||||
"/address/create",
|
||||
"/address/update",
|
||||
"/postcode/create",
|
||||
"/postcode/update",
|
||||
"/postcode/list",
|
||||
"/address/search",
|
||||
];
|
||||
|
||||
export { IdentityAllEndpoints, IdentitySelfEndpoints, AddressAllEndpoints };
|
||||
69
apimaps/identity/subCategories.tsx
Normal file
69
apimaps/identity/subCategories.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import { AddressAllEndpoints } from "./pageInfo";
|
||||
import { PeoplePageInfo } from "../people/pageInfo";
|
||||
|
||||
const AddressSubCategories = [
|
||||
{
|
||||
title: {
|
||||
tr: "Posta Kodları",
|
||||
en: "Postcodes",
|
||||
},
|
||||
icon: "Container",
|
||||
component: null,
|
||||
selfEndpoints: ["/postcode/list", "/postcode/create", "/postcode/update"],
|
||||
allEndpoints: [],
|
||||
subCategories: [],
|
||||
},
|
||||
{
|
||||
title: {
|
||||
tr: "Adres Arama",
|
||||
en: "Address Search",
|
||||
},
|
||||
icon: "ScanSearch",
|
||||
component: null,
|
||||
selfEndpoints: ["/address/search", "/address/list"],
|
||||
allEndpoints: [],
|
||||
subCategories: [],
|
||||
},
|
||||
];
|
||||
|
||||
const IdentityCategories = [
|
||||
{
|
||||
title: {
|
||||
tr: "Kullanıcılar",
|
||||
en: "Users",
|
||||
},
|
||||
icon: "UserPlus",
|
||||
component: null,
|
||||
selfEndpoints: [
|
||||
"/users/list",
|
||||
"/users/create",
|
||||
"/users/update/{user_uu_id}",
|
||||
],
|
||||
allEndpoints: [],
|
||||
subCategories: [],
|
||||
},
|
||||
{
|
||||
title: {
|
||||
tr: "İnsanlar",
|
||||
en: "People",
|
||||
},
|
||||
icon: "PersonStanding",
|
||||
component: "PeoplePage",
|
||||
pageInfo: PeoplePageInfo,
|
||||
allEndpoints: [],
|
||||
subCategories: [],
|
||||
},
|
||||
{
|
||||
title: {
|
||||
tr: "Adresler",
|
||||
en: "Addresses",
|
||||
},
|
||||
icon: "MapPinned",
|
||||
component: null,
|
||||
selfEndpoints: ["/address/list", "/address/create", "/address/update"],
|
||||
allEndpoints: AddressAllEndpoints,
|
||||
subCategories: AddressSubCategories,
|
||||
},
|
||||
];
|
||||
|
||||
export { IdentityCategories };
|
||||
50
apimaps/livingSpace/pageInfo.ts
Normal file
50
apimaps/livingSpace/pageInfo.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
const LivingSpaceInfo = {
|
||||
tr: [
|
||||
{
|
||||
title: "Yaşayan Kişiler Listesi",
|
||||
icon: null,
|
||||
description: "Yaşayan Kişiler listeyebilirsiniz",
|
||||
endpoint: "/building/living_space/list",
|
||||
component: "Table",
|
||||
},
|
||||
{
|
||||
title: "Yaşayan Kişi Ekle",
|
||||
icon: "BadgePlus",
|
||||
description: "Yaşayan Kişi oluşturma sayfasına hoş geldiniz",
|
||||
endpoint: "/building/living_space/create",
|
||||
component: "AddCreate2Table",
|
||||
},
|
||||
{
|
||||
title: null,
|
||||
icon: "Pencil",
|
||||
description: "Yaşayan Kişi güncelleme sayfasına hoş geldiniz",
|
||||
endpoint: "/building/living_space/update/{build_uu_id}",
|
||||
component: "AddUpdate2Table",
|
||||
},
|
||||
],
|
||||
en: [
|
||||
{
|
||||
title: "Living People List",
|
||||
icon: null,
|
||||
description: "Welcome to the living people update page",
|
||||
endpoint: "/building/living_space/list",
|
||||
component: "Table",
|
||||
},
|
||||
{
|
||||
title: "Create Living People",
|
||||
icon: "BadgePlus",
|
||||
description: "Welcome to the living people creation page",
|
||||
endpoint: "/building/living_space/create",
|
||||
component: "AddCreate2Table",
|
||||
},
|
||||
{
|
||||
title: "Update Living People",
|
||||
icon: "Pencil",
|
||||
description: "Welcome to the living people update page",
|
||||
endpoint: "/building/living_space/update/{build_uu_id}",
|
||||
component: "AddUpdate2Table",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export { LivingSpaceInfo };
|
||||
113
apimaps/mappingApi.ts
Normal file
113
apimaps/mappingApi.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import { BuildCategories } from "./building/subCategories";
|
||||
import { MeetingSubCategories } from "./meeting/subCategories";
|
||||
import { AccountSubCategories } from "./accounts/subCategories";
|
||||
import { DecisionBookSubCategories } from "./decisionBook/subCategories";
|
||||
import { AccesibleCategories } from "./accesible/subCategories";
|
||||
import { CompanyCategories } from "./company/subCategories";
|
||||
import { IdentityCategories } from "./identity/subCategories";
|
||||
import {
|
||||
DecisionBookAllEndpoints,
|
||||
DecisionBookPageInfo,
|
||||
} from "./decisionBook/pageInfo";
|
||||
import { IdentityAllEndpoints } from "./identity/pageInfo";
|
||||
import { AccesibleAllEndpoints } from "./accesible/pageInfo";
|
||||
import { CompanyAllEndpoints, CompanyPageInfo } from "./company/pageInfo";
|
||||
import { MeetingAllEndpoints } from "./meeting/pageInfo";
|
||||
import { AccountAllEndpoints, AccountPageInfo } from "./accounts/pageInfo";
|
||||
import { BuildPageInfo, BuildAllEndpoints } from "./building/pageInfo";
|
||||
|
||||
const PagesInfosAndEndpoints = [
|
||||
{
|
||||
title: {
|
||||
tr: "Binalar",
|
||||
en: "Buildings",
|
||||
},
|
||||
icon: "Hotel",
|
||||
// component: "/build/page",
|
||||
url: "/building?page=1",
|
||||
pageInfo: BuildPageInfo,
|
||||
allEndpoints: BuildAllEndpoints,
|
||||
subCategories: BuildCategories,
|
||||
},
|
||||
{
|
||||
title: {
|
||||
tr: "Toplantılar",
|
||||
en: "Meetings",
|
||||
},
|
||||
icon: "Logs",
|
||||
url: "/meetings?page=1",
|
||||
pageInfo: null,
|
||||
component: null,
|
||||
allEndpoints: MeetingAllEndpoints,
|
||||
subCategories: MeetingSubCategories,
|
||||
},
|
||||
{
|
||||
title: {
|
||||
tr: "Cari Hesaplar",
|
||||
en: "Accounts",
|
||||
},
|
||||
icon: "Landmark",
|
||||
component: "AccountPage",
|
||||
url: "/accounts?page=1",
|
||||
pageInfo: AccountPageInfo,
|
||||
allEndpoints: AccountAllEndpoints,
|
||||
subCategories: AccountSubCategories,
|
||||
},
|
||||
{
|
||||
title: {
|
||||
tr: "Karar Defteri",
|
||||
en: "Decision Book",
|
||||
},
|
||||
icon: "ScrollText",
|
||||
component: "DecisionBookPage",
|
||||
url: "/decisions?page=1",
|
||||
pageInfo: DecisionBookPageInfo,
|
||||
allEndpoints: DecisionBookAllEndpoints,
|
||||
subCategories: DecisionBookSubCategories,
|
||||
},
|
||||
{
|
||||
title: {
|
||||
tr: "Kimlikler",
|
||||
en: "Identities",
|
||||
},
|
||||
icon: "UserPlus",
|
||||
component: null,
|
||||
url: "/identities?page=1",
|
||||
pageInfo: null,
|
||||
allEndpoints: IdentityAllEndpoints,
|
||||
subCategories: IdentityCategories,
|
||||
},
|
||||
{
|
||||
title: {
|
||||
tr: "Erişilebilirlik",
|
||||
en: "Accessibility",
|
||||
},
|
||||
icon: "Cog",
|
||||
component: null,
|
||||
url: "/accessibilities?page=1",
|
||||
pageInfo: null,
|
||||
allEndpoints: AccesibleAllEndpoints,
|
||||
subCategories: AccesibleCategories,
|
||||
},
|
||||
{
|
||||
title: {
|
||||
tr: "Firmalar",
|
||||
en: "Companies",
|
||||
},
|
||||
icon: "Store",
|
||||
component: "CompanyPage",
|
||||
url: "/companies?page=1",
|
||||
pageInfo: CompanyPageInfo,
|
||||
allEndpoints: CompanyAllEndpoints,
|
||||
subCategories: CompanyCategories,
|
||||
},
|
||||
];
|
||||
|
||||
const AvailableLanguages = ["tr", "en"];
|
||||
interface LanguagesInterface {
|
||||
tr: string;
|
||||
en: string;
|
||||
}
|
||||
|
||||
export type { LanguagesInterface };
|
||||
export { PagesInfosAndEndpoints, AvailableLanguages };
|
||||
40
apimaps/mappingApiFunctions.ts
Normal file
40
apimaps/mappingApiFunctions.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { PagesInfosAndEndpoints } from "./mappingApi";
|
||||
|
||||
export function retrieveAvailableCategories(availableCategories: any) {
|
||||
const availableCategoriesList = Array.from(
|
||||
availableCategories?.availableEvents || []
|
||||
);
|
||||
let availableMenu: Array<any> = [];
|
||||
|
||||
for (let i = 0; i < PagesInfosAndEndpoints.length; i++) {
|
||||
const category = PagesInfosAndEndpoints[i];
|
||||
if (category.allEndpoints) {
|
||||
const setCategory = isCategoryAvailable(
|
||||
category,
|
||||
availableCategoriesList
|
||||
);
|
||||
if (setCategory) {
|
||||
availableMenu.push(category);
|
||||
}
|
||||
}
|
||||
}
|
||||
return availableMenu;
|
||||
}
|
||||
|
||||
function isCategoryAvailable(category: any, availableCategoriesList: any) {
|
||||
const categoryList = Array.from(category.allEndpoints);
|
||||
for (let j = 0; j < categoryList.length; j++) {
|
||||
const endpoint = categoryList[j];
|
||||
if (availableCategoriesList.includes(endpoint)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function checkEndpointAvailability(
|
||||
endpoint: string,
|
||||
availableCategories: any
|
||||
) {
|
||||
const availableCategoriesList = Array.from(availableCategories || []);
|
||||
return availableCategoriesList.includes(endpoint);
|
||||
}
|
||||
8
apimaps/meeting/pageInfo.ts
Normal file
8
apimaps/meeting/pageInfo.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
const MeetingAllEndpoints = [
|
||||
"/build/decision_book/invite/list",
|
||||
"/build/decision_book/invite/create",
|
||||
"/build/decision_book/invite/update",
|
||||
"/build/decision_book/invitations/assign",
|
||||
];
|
||||
|
||||
export { MeetingAllEndpoints };
|
||||
31
apimaps/meeting/subCategories.tsx
Normal file
31
apimaps/meeting/subCategories.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
const MeetingSubCategories = [
|
||||
{
|
||||
title: {
|
||||
tr: "Davetiyeler",
|
||||
en: "Invitations",
|
||||
},
|
||||
icon: "ClipboardCheck",
|
||||
component: null,
|
||||
selfEndpoints: [
|
||||
"/build/decision_book/invite/list",
|
||||
"/build/decision_book/invite/create",
|
||||
"/build/decision_book/invite/update",
|
||||
"/build/decision_book/invitations/assign",
|
||||
],
|
||||
allEndpoints: [],
|
||||
subCategories: [],
|
||||
},
|
||||
{
|
||||
title: {
|
||||
tr: "Görev Ata",
|
||||
en: "Assign Task",
|
||||
},
|
||||
icon: "ClipboardList",
|
||||
component: null,
|
||||
selfEndpoints: [],
|
||||
allEndpoints: [],
|
||||
subCategories: [],
|
||||
},
|
||||
];
|
||||
|
||||
export { MeetingSubCategories };
|
||||
50
apimaps/parts/pageInfo.ts
Normal file
50
apimaps/parts/pageInfo.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
const PartsPageInfo = {
|
||||
tr: [
|
||||
{
|
||||
title: "Daire Listesi",
|
||||
icon: null,
|
||||
description: "Daireleri listeyebilirsiniz",
|
||||
endpoint: "/building/parts/list",
|
||||
component: "Table",
|
||||
},
|
||||
{
|
||||
title: "Daire Oluştur",
|
||||
icon: "BadgePlus",
|
||||
description: "Daire oluşturabilirsiniz",
|
||||
endpoint: "/building/parts/create",
|
||||
component: "Form",
|
||||
},
|
||||
{
|
||||
title: "Daire Güncelle",
|
||||
icon: "Pencil",
|
||||
description: "Daire güncelleyebilirsiniz",
|
||||
endpoint: "/building/parts/update/{build_uu_id}",
|
||||
component: "Form",
|
||||
},
|
||||
],
|
||||
en: [
|
||||
{
|
||||
title: "Flat List",
|
||||
icon: null,
|
||||
description: "You can list the flats",
|
||||
endpoint: "/building/parts/list",
|
||||
component: "Table",
|
||||
},
|
||||
{
|
||||
title: "Create Flat",
|
||||
icon: "BadgePlus",
|
||||
description: "You can create a flat",
|
||||
endpoint: "/building/parts/create",
|
||||
component: "Form",
|
||||
},
|
||||
{
|
||||
title: "Update Flat",
|
||||
icon: "Pencil",
|
||||
description: "You can update a flat",
|
||||
endpoint: "/building/parts/update/{build_uu_id}",
|
||||
component: "Form",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export { PartsPageInfo };
|
||||
50
apimaps/people/pageInfo.ts
Normal file
50
apimaps/people/pageInfo.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
const PeoplePageInfo = {
|
||||
tr: [
|
||||
{
|
||||
title: "Kişileri Listele",
|
||||
icon: null,
|
||||
description: "Kişileri listeyebilirsiniz",
|
||||
endpoint: "/people/list",
|
||||
component: "Table",
|
||||
},
|
||||
{
|
||||
title: "Kişi Oluştur",
|
||||
icon: "BadgePlus",
|
||||
description: "Kişi oluşturabilirsiniz",
|
||||
endpoint: "/people/create",
|
||||
component: "Form",
|
||||
},
|
||||
{
|
||||
title: "Kişi Güncelle",
|
||||
icon: "Pencil",
|
||||
description: "Kişi güncelleyebilirsiniz",
|
||||
endpoint: "/people/update/{build_uu_id}",
|
||||
component: "Form",
|
||||
},
|
||||
],
|
||||
en: [
|
||||
{
|
||||
title: "People List",
|
||||
icon: null,
|
||||
description: "You can list the people",
|
||||
endpoint: "/people/list",
|
||||
component: "Table",
|
||||
},
|
||||
{
|
||||
title: "Create People",
|
||||
icon: "BadgePlus",
|
||||
description: "You can create a people",
|
||||
endpoint: "/people/create",
|
||||
component: "Form",
|
||||
},
|
||||
{
|
||||
title: "Update People",
|
||||
icon: "Pencil",
|
||||
description: "You can update a people",
|
||||
endpoint: "/people/update/{build_uu_id}",
|
||||
component: "Form",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export { PeoplePageInfo };
|
||||
21
components.json
Normal file
21
components.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "new-york",
|
||||
"rsc": true,
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "tailwind.config.ts",
|
||||
"css": "src/app/globals.css",
|
||||
"baseColor": "neutral",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
},
|
||||
"aliases": {
|
||||
"components": "@/components",
|
||||
"utils": "@/lib/utils",
|
||||
"ui": "@/components/ui",
|
||||
"lib": "@/lib",
|
||||
"hooks": "@/hooks"
|
||||
},
|
||||
"iconLibrary": "lucide"
|
||||
}
|
||||
7
next.config.ts
Normal file
7
next.config.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
/* config options here */
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
3036
package-lock.json
generated
Normal file
3036
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
43
package.json
Normal file
43
package.json
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"name": "wag-frontend-version-3",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^3.9.1",
|
||||
"@radix-ui/react-label": "^2.1.1",
|
||||
"@radix-ui/react-popover": "^1.1.4",
|
||||
"@radix-ui/react-scroll-area": "^1.2.2",
|
||||
"@radix-ui/react-slot": "^1.1.1",
|
||||
"@radix-ui/react-switch": "^1.1.2",
|
||||
"@tanstack/react-table": "^8.20.6",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"flatpickr": "^4.6.13",
|
||||
"lucide-react": "^0.469.0",
|
||||
"next": "15.1.2",
|
||||
"next-crypto": "^1.0.8",
|
||||
"react": "^19.0.0",
|
||||
"react-day-picker": "^8.10.1",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-hook-form": "^7.54.2",
|
||||
"sonner": "^1.7.1",
|
||||
"tailwind-merge": "^2.6.0",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"zod": "^3.24.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"postcss": "^8",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
||||
8
postcss.config.mjs
Normal file
8
postcss.config.mjs
Normal file
@@ -0,0 +1,8 @@
|
||||
/** @type {import('postcss-load-config').Config} */
|
||||
const config = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
1
public/file.svg
Normal file
1
public/file.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
|
||||
|
After Width: | Height: | Size: 391 B |
1
public/globe.svg
Normal file
1
public/globe.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
1
public/next.svg
Normal file
1
public/next.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
1
public/vercel.svg
Normal file
1
public/vercel.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 128 B |
1
public/window.svg
Normal file
1
public/window.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
|
||||
|
After Width: | Height: | Size: 385 B |
15
src/app/building/page.tsx
Normal file
15
src/app/building/page.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
"use server";
|
||||
import React from "react";
|
||||
|
||||
const Page = () => {
|
||||
return (
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<h1 className="text-2xl font-bold mb-4">Building Management</h1>
|
||||
<div className="bg-white rounded-lg shadow p-6">
|
||||
<p>Building page content goes here</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Page;
|
||||
17
src/app/dashboard/page.tsx
Normal file
17
src/app/dashboard/page.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
"use server";
|
||||
import React from "react";
|
||||
|
||||
const DashboardPage = () => {
|
||||
return (
|
||||
<div className="p-4">
|
||||
<h1 className="text-2xl font-bold mb-4">Dashboard</h1>
|
||||
<div className="grid gap-4">
|
||||
<div className="bg-white p-4 rounded-lg shadow">
|
||||
<p>Welcome to your dashboard</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DashboardPage;
|
||||
BIN
src/app/favicon.ico
Normal file
BIN
src/app/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
72
src/app/globals.css
Normal file
72
src/app/globals.css
Normal file
@@ -0,0 +1,72 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
body {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 0 0% 3.9%;
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 0 0% 3.9%;
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 0 0% 3.9%;
|
||||
--primary: 0 0% 9%;
|
||||
--primary-foreground: 0 0% 98%;
|
||||
--secondary: 0 0% 96.1%;
|
||||
--secondary-foreground: 0 0% 9%;
|
||||
--muted: 0 0% 96.1%;
|
||||
--muted-foreground: 0 0% 45.1%;
|
||||
--accent: 0 0% 96.1%;
|
||||
--accent-foreground: 0 0% 9%;
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 0 0% 89.8%;
|
||||
--input: 0 0% 89.8%;
|
||||
--ring: 0 0% 3.9%;
|
||||
--chart-1: 12 76% 61%;
|
||||
--chart-2: 173 58% 39%;
|
||||
--chart-3: 197 37% 24%;
|
||||
--chart-4: 43 74% 66%;
|
||||
--chart-5: 27 87% 67%;
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
.dark {
|
||||
--background: 0 0% 3.9%;
|
||||
--foreground: 0 0% 98%;
|
||||
--card: 0 0% 3.9%;
|
||||
--card-foreground: 0 0% 98%;
|
||||
--popover: 0 0% 3.9%;
|
||||
--popover-foreground: 0 0% 98%;
|
||||
--primary: 0 0% 98%;
|
||||
--primary-foreground: 0 0% 9%;
|
||||
--secondary: 0 0% 14.9%;
|
||||
--secondary-foreground: 0 0% 98%;
|
||||
--muted: 0 0% 14.9%;
|
||||
--muted-foreground: 0 0% 63.9%;
|
||||
--accent: 0 0% 14.9%;
|
||||
--accent-foreground: 0 0% 98%;
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 0 0% 14.9%;
|
||||
--input: 0 0% 14.9%;
|
||||
--ring: 0 0% 83.1%;
|
||||
--chart-1: 220 70% 50%;
|
||||
--chart-2: 160 60% 45%;
|
||||
--chart-3: 30 80% 55%;
|
||||
--chart-4: 280 65% 60%;
|
||||
--chart-5: 340 75% 55%;
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
34
src/app/layout.tsx
Normal file
34
src/app/layout.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
import "./globals.css";
|
||||
|
||||
const geistSans = Geist({
|
||||
variable: "--font-geist-sans",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
const geistMono = Geist_Mono({
|
||||
variable: "--font-geist-mono",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Evyos Web App",
|
||||
description: "Generated by evyos app",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||
>
|
||||
{children}
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
18
src/app/login/email/page.tsx
Normal file
18
src/app/login/email/page.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
"use server";
|
||||
|
||||
import { checkAccessTokenIsValid } from "@/apicalls/cookies/token";
|
||||
import LoginWithEmail from "@/pages/LoginViaEmail/page";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
const LoginEmailPage = async () => {
|
||||
if (await checkAccessTokenIsValid()) {
|
||||
redirect("/login/select");
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<LoginWithEmail />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoginEmailPage;
|
||||
14
src/app/login/page.tsx
Normal file
14
src/app/login/page.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
"use server";
|
||||
|
||||
import { checkAccessTokenIsValid } from "@/apicalls/cookies/token";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
const LoginPage = async () => {
|
||||
if (await checkAccessTokenIsValid()) {
|
||||
redirect("/login/select");
|
||||
} else {
|
||||
redirect("/login/email");
|
||||
}
|
||||
};
|
||||
|
||||
export default LoginPage;
|
||||
17
src/app/login/phone/page.tsx
Normal file
17
src/app/login/phone/page.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
"use server";
|
||||
import { checkAccessTokenIsValid } from "@/apicalls/cookies/token";
|
||||
import { redirect } from "next/navigation";
|
||||
import LoginWithPhone from "@/pages/LoginViaPhone/page";
|
||||
|
||||
const LoginPhonePage = async () => {
|
||||
if (await checkAccessTokenIsValid()) {
|
||||
redirect("/login/select");
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<LoginWithPhone />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoginPhonePage;
|
||||
27
src/app/login/select/LoginEmployeePage.tsx
Normal file
27
src/app/login/select/LoginEmployeePage.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
"use server";
|
||||
import React from "react";
|
||||
import { retrieveAccessObjects } from "@/apicalls/cookies/token";
|
||||
import LoginSelectEmployeeCard from "@/pages/LoginSelectEmployee/page";
|
||||
|
||||
const LoginEmployeePage: React.FC = async () => {
|
||||
const accessObject = await retrieveAccessObjects();
|
||||
return accessObject ? (
|
||||
<>
|
||||
<div className="absolute top-0 left-0 min-w-full min-h-full">
|
||||
<div className="rounded-sm border border-stroke bg-white shadow-default dark:border-strokedark dark:bg-boxdark">
|
||||
<div className="flex flex-wrap items-center">
|
||||
<LoginSelectEmployeeCard
|
||||
companyList={accessObject.companies_list}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<h1>No register Employeer Company has found for this user</h1>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoginEmployeePage;
|
||||
27
src/app/login/select/LoginOccupantPage.tsx
Normal file
27
src/app/login/select/LoginOccupantPage.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
"use server";
|
||||
import React from "react";
|
||||
import { retrieveAccessObjects } from "@/apicalls/cookies/token";
|
||||
import LoginSelectOccupantCard from "@/pages/LoginSelectOccupant/page";
|
||||
|
||||
const LoginOccupantPage: React.FC = async () => {
|
||||
const accessObject: any = await retrieveAccessObjects();
|
||||
return accessObject ? (
|
||||
<>
|
||||
<div className="absolute top-0 left-0 min-w-full min-h-full">
|
||||
<div className="rounded-sm border border-stroke bg-white shadow-default dark:border-strokedark dark:bg-boxdark">
|
||||
<div className="flex flex-wrap items-center">
|
||||
<LoginSelectOccupantCard
|
||||
availableOccupants={accessObject?.available_occupants}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<h1>No register Occupant has found for this user</h1>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoginOccupantPage;
|
||||
22
src/app/login/select/page.tsx
Normal file
22
src/app/login/select/page.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
"use server";
|
||||
import {
|
||||
checkAccessTokenIsValid,
|
||||
retrieveUserType,
|
||||
} from "@/apicalls/cookies/token";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
import LoginEmployeePage from "./LoginEmployeePage";
|
||||
import LoginOccupantPage from "./LoginOccupantPage";
|
||||
|
||||
const SelectPage = async () => {
|
||||
const token_is_valid = await checkAccessTokenIsValid();
|
||||
const userType: "employee" | "occupant" = await retrieveUserType();
|
||||
const isEmployee = userType === "employee";
|
||||
|
||||
if (!userType || !token_is_valid) {
|
||||
redirect("/login/email");
|
||||
}
|
||||
return <>{isEmployee ? <LoginEmployeePage /> : <LoginOccupantPage />}</>;
|
||||
};
|
||||
|
||||
export default SelectPage;
|
||||
101
src/app/page.tsx
Normal file
101
src/app/page.tsx
Normal file
@@ -0,0 +1,101 @@
|
||||
import Image from "next/image";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
|
||||
<main className="flex flex-col gap-8 row-start-2 items-center sm:items-start">
|
||||
<Image
|
||||
className="dark:invert"
|
||||
src="/next.svg"
|
||||
alt="Next.js logo"
|
||||
width={180}
|
||||
height={38}
|
||||
priority
|
||||
/>
|
||||
<ol className="list-inside list-decimal text-sm text-center sm:text-left font-[family-name:var(--font-geist-mono)]">
|
||||
<li className="mb-2">
|
||||
Get started by editing{" "}
|
||||
<code className="bg-black/[.05] dark:bg-white/[.06] px-1 py-0.5 rounded font-semibold">
|
||||
src/app/page.tsx
|
||||
</code>
|
||||
.
|
||||
</li>
|
||||
<li>Save and see your changes instantly.</li>
|
||||
</ol>
|
||||
|
||||
<div className="flex gap-4 items-center flex-col sm:flex-row">
|
||||
<a
|
||||
className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5"
|
||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
className="dark:invert"
|
||||
src="/vercel.svg"
|
||||
alt="Vercel logomark"
|
||||
width={20}
|
||||
height={20}
|
||||
/>
|
||||
Deploy now
|
||||
</a>
|
||||
<a
|
||||
className="rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:min-w-44"
|
||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Read our docs
|
||||
</a>
|
||||
</div>
|
||||
</main>
|
||||
<footer className="row-start-3 flex gap-6 flex-wrap items-center justify-center">
|
||||
<a
|
||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
aria-hidden
|
||||
src="/file.svg"
|
||||
alt="File icon"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
Learn
|
||||
</a>
|
||||
<a
|
||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
aria-hidden
|
||||
src="/window.svg"
|
||||
alt="Window icon"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
Examples
|
||||
</a>
|
||||
<a
|
||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||
href="https://nextjs.org?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
aria-hidden
|
||||
src="/globe.svg"
|
||||
alt="Globe icon"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
Go to nextjs.org →
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
84
src/components/login/buttons.tsx
Normal file
84
src/components/login/buttons.tsx
Normal file
@@ -0,0 +1,84 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
const GoogleButton: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
<button className="flex w-full items-center justify-center gap-3.5 rounded-lg border border-stroke bg-gray p-4 hover:bg-opacity-50 dark:border-strokedark dark:bg-meta-4 dark:hover:bg-opacity-50">
|
||||
<span>
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g clipPath="url(#clip0_191_13499)">
|
||||
<path
|
||||
d="M19.999 10.2217C20.0111 9.53428 19.9387 8.84788 19.7834 8.17737H10.2031V11.8884H15.8266C15.7201 12.5391 15.4804 13.162 15.1219 13.7195C14.7634 14.2771 14.2935 14.7578 13.7405 15.1328L13.7209 15.2571L16.7502 17.5568L16.96 17.5774C18.8873 15.8329 19.9986 13.2661 19.9986 10.2217"
|
||||
fill="#4285F4"
|
||||
/>
|
||||
<path
|
||||
d="M10.2055 19.9999C12.9605 19.9999 15.2734 19.111 16.9629 17.5777L13.7429 15.1331C12.8813 15.7221 11.7248 16.1333 10.2055 16.1333C8.91513 16.1259 7.65991 15.7205 6.61791 14.9745C5.57592 14.2286 4.80007 13.1801 4.40044 11.9777L4.28085 11.9877L1.13101 14.3765L1.08984 14.4887C1.93817 16.1456 3.24007 17.5386 4.84997 18.5118C6.45987 19.4851 8.31429 20.0004 10.2059 19.9999"
|
||||
fill="#34A853"
|
||||
/>
|
||||
<path
|
||||
d="M4.39899 11.9777C4.1758 11.3411 4.06063 10.673 4.05807 9.99996C4.06218 9.32799 4.1731 8.66075 4.38684 8.02225L4.38115 7.88968L1.19269 5.4624L1.0884 5.51101C0.372763 6.90343 0 8.4408 0 9.99987C0 11.5589 0.372763 13.0963 1.0884 14.4887L4.39899 11.9777Z"
|
||||
fill="#FBBC05"
|
||||
/>
|
||||
<path
|
||||
d="M10.2059 3.86663C11.668 3.84438 13.0822 4.37803 14.1515 5.35558L17.0313 2.59996C15.1843 0.901848 12.7383 -0.0298855 10.2059 -3.6784e-05C8.31431 -0.000477834 6.4599 0.514732 4.85001 1.48798C3.24011 2.46124 1.9382 3.85416 1.08984 5.51101L4.38946 8.02225C4.79303 6.82005 5.57145 5.77231 6.61498 5.02675C7.65851 4.28118 8.9145 3.87541 10.2059 3.86663Z"
|
||||
fill="#EB4335"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_191_13499">
|
||||
<rect width="20" height="20" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
</span>
|
||||
Google ile giriş yap
|
||||
</button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const LoginButton: React.FC = () => {
|
||||
return (
|
||||
<div className="mb-5">
|
||||
<input
|
||||
type="submit"
|
||||
value="Giriş Yap"
|
||||
className="w-full cursor-pointer rounded-lg border border-primary bg-primary p-4 text-white transition hover:bg-opacity-90"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface InterfaceChangeSignTypeButton {
|
||||
buttonType: "phone" | "email";
|
||||
}
|
||||
const ChangeSignTypeButton: React.FC<InterfaceChangeSignTypeButton> = ({
|
||||
buttonType,
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<div className="my-5">
|
||||
<button
|
||||
className="w-full cursor-pointer rounded-lg border border-primary bg-primary p-4 text-white transition hover:bg-opacity-90"
|
||||
onClick={() =>
|
||||
router.push(buttonType === "phone" ? "/login/phone" : "/login/email")
|
||||
}
|
||||
>
|
||||
{buttonType === "phone"
|
||||
? "Telefon ile Giriş Yap"
|
||||
: "Email ile Giriş Yap"}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export { GoogleButton, LoginButton, ChangeSignTypeButton };
|
||||
33
src/components/login/leftsidepanel.tsx
Normal file
33
src/components/login/leftsidepanel.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import React from "react";
|
||||
import Image from "next/image";
|
||||
|
||||
interface InterfaceLeftSidePanel {
|
||||
textLabel: string;
|
||||
}
|
||||
|
||||
const LeftSidePanel: React.FC<InterfaceLeftSidePanel> = ({
|
||||
textLabel
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<div className="hidden w-full xl:block xl:w-1/2">
|
||||
<div className="text-center">
|
||||
<p className="text-xl 2xl:px-20 my-5 text-black dark:text-white">
|
||||
{textLabel}
|
||||
</p>
|
||||
<span className="mt-15 inline-block">
|
||||
<Image
|
||||
src="/green-house.webp"
|
||||
alt="login-image"
|
||||
width={480}
|
||||
height={480}
|
||||
className="w-108 h-108 mt-5"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default LeftSidePanel;
|
||||
57
src/components/ui/button.tsx
Normal file
57
src/components/ui/button.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
import * as React from "react"
|
||||
import { Slot } from "@radix-ui/react-slot"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
||||
destructive:
|
||||
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
||||
outline:
|
||||
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
|
||||
secondary:
|
||||
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||
link: "text-primary underline-offset-4 hover:underline",
|
||||
},
|
||||
size: {
|
||||
default: "h-9 px-4 py-2",
|
||||
sm: "h-8 rounded-md px-3 text-xs",
|
||||
lg: "h-10 rounded-md px-8",
|
||||
icon: "h-9 w-9",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
export interface ButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
VariantProps<typeof buttonVariants> {
|
||||
asChild?: boolean
|
||||
}
|
||||
|
||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : "button"
|
||||
return (
|
||||
<Comp
|
||||
className={cn(buttonVariants({ variant, size, className }))}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
Button.displayName = "Button"
|
||||
|
||||
export { Button, buttonVariants }
|
||||
76
src/components/ui/calendar.tsx
Normal file
76
src/components/ui/calendar.tsx
Normal file
@@ -0,0 +1,76 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { ChevronLeft, ChevronRight } from "lucide-react"
|
||||
import { DayPicker } from "react-day-picker"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { buttonVariants } from "@/components/ui/button"
|
||||
|
||||
export type CalendarProps = React.ComponentProps<typeof DayPicker>
|
||||
|
||||
function Calendar({
|
||||
className,
|
||||
classNames,
|
||||
showOutsideDays = true,
|
||||
...props
|
||||
}: CalendarProps) {
|
||||
return (
|
||||
<DayPicker
|
||||
showOutsideDays={showOutsideDays}
|
||||
className={cn("p-3", className)}
|
||||
classNames={{
|
||||
months: "flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0",
|
||||
month: "space-y-4",
|
||||
caption: "flex justify-center pt-1 relative items-center",
|
||||
caption_label: "text-sm font-medium",
|
||||
nav: "space-x-1 flex items-center",
|
||||
nav_button: cn(
|
||||
buttonVariants({ variant: "outline" }),
|
||||
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100"
|
||||
),
|
||||
nav_button_previous: "absolute left-1",
|
||||
nav_button_next: "absolute right-1",
|
||||
table: "w-full border-collapse space-y-1",
|
||||
head_row: "flex",
|
||||
head_cell:
|
||||
"text-muted-foreground rounded-md w-8 font-normal text-[0.8rem]",
|
||||
row: "flex w-full mt-2",
|
||||
cell: cn(
|
||||
"relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-accent [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected].day-range-end)]:rounded-r-md",
|
||||
props.mode === "range"
|
||||
? "[&:has(>.day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md"
|
||||
: "[&:has([aria-selected])]:rounded-md"
|
||||
),
|
||||
day: cn(
|
||||
buttonVariants({ variant: "ghost" }),
|
||||
"h-8 w-8 p-0 font-normal aria-selected:opacity-100"
|
||||
),
|
||||
day_range_start: "day-range-start",
|
||||
day_range_end: "day-range-end",
|
||||
day_selected:
|
||||
"bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
|
||||
day_today: "bg-accent text-accent-foreground",
|
||||
day_outside:
|
||||
"day-outside text-muted-foreground aria-selected:bg-accent/50 aria-selected:text-muted-foreground",
|
||||
day_disabled: "text-muted-foreground opacity-50",
|
||||
day_range_middle:
|
||||
"aria-selected:bg-accent aria-selected:text-accent-foreground",
|
||||
day_hidden: "invisible",
|
||||
...classNames,
|
||||
}}
|
||||
components={{
|
||||
IconLeft: ({ className, ...props }) => (
|
||||
<ChevronLeft className={cn("h-4 w-4", className)} {...props} />
|
||||
),
|
||||
IconRight: ({ className, ...props }) => (
|
||||
<ChevronRight className={cn("h-4 w-4", className)} {...props} />
|
||||
),
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
Calendar.displayName = "Calendar"
|
||||
|
||||
export { Calendar }
|
||||
178
src/components/ui/form.tsx
Normal file
178
src/components/ui/form.tsx
Normal file
@@ -0,0 +1,178 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as LabelPrimitive from "@radix-ui/react-label"
|
||||
import { Slot } from "@radix-ui/react-slot"
|
||||
import {
|
||||
Controller,
|
||||
ControllerProps,
|
||||
FieldPath,
|
||||
FieldValues,
|
||||
FormProvider,
|
||||
useFormContext,
|
||||
} from "react-hook-form"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Label } from "@/components/ui/label"
|
||||
|
||||
const Form = FormProvider
|
||||
|
||||
type FormFieldContextValue<
|
||||
TFieldValues extends FieldValues = FieldValues,
|
||||
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
|
||||
> = {
|
||||
name: TName
|
||||
}
|
||||
|
||||
const FormFieldContext = React.createContext<FormFieldContextValue>(
|
||||
{} as FormFieldContextValue
|
||||
)
|
||||
|
||||
const FormField = <
|
||||
TFieldValues extends FieldValues = FieldValues,
|
||||
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
|
||||
>({
|
||||
...props
|
||||
}: ControllerProps<TFieldValues, TName>) => {
|
||||
return (
|
||||
<FormFieldContext.Provider value={{ name: props.name }}>
|
||||
<Controller {...props} />
|
||||
</FormFieldContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
const useFormField = () => {
|
||||
const fieldContext = React.useContext(FormFieldContext)
|
||||
const itemContext = React.useContext(FormItemContext)
|
||||
const { getFieldState, formState } = useFormContext()
|
||||
|
||||
const fieldState = getFieldState(fieldContext.name, formState)
|
||||
|
||||
if (!fieldContext) {
|
||||
throw new Error("useFormField should be used within <FormField>")
|
||||
}
|
||||
|
||||
const { id } = itemContext
|
||||
|
||||
return {
|
||||
id,
|
||||
name: fieldContext.name,
|
||||
formItemId: `${id}-form-item`,
|
||||
formDescriptionId: `${id}-form-item-description`,
|
||||
formMessageId: `${id}-form-item-message`,
|
||||
...fieldState,
|
||||
}
|
||||
}
|
||||
|
||||
type FormItemContextValue = {
|
||||
id: string
|
||||
}
|
||||
|
||||
const FormItemContext = React.createContext<FormItemContextValue>(
|
||||
{} as FormItemContextValue
|
||||
)
|
||||
|
||||
const FormItem = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => {
|
||||
const id = React.useId()
|
||||
|
||||
return (
|
||||
<FormItemContext.Provider value={{ id }}>
|
||||
<div ref={ref} className={cn("space-y-2", className)} {...props} />
|
||||
</FormItemContext.Provider>
|
||||
)
|
||||
})
|
||||
FormItem.displayName = "FormItem"
|
||||
|
||||
const FormLabel = React.forwardRef<
|
||||
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { error, formItemId } = useFormField()
|
||||
|
||||
return (
|
||||
<Label
|
||||
ref={ref}
|
||||
className={cn(error && "text-destructive", className)}
|
||||
htmlFor={formItemId}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
FormLabel.displayName = "FormLabel"
|
||||
|
||||
const FormControl = React.forwardRef<
|
||||
React.ElementRef<typeof Slot>,
|
||||
React.ComponentPropsWithoutRef<typeof Slot>
|
||||
>(({ ...props }, ref) => {
|
||||
const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
|
||||
|
||||
return (
|
||||
<Slot
|
||||
ref={ref}
|
||||
id={formItemId}
|
||||
aria-describedby={
|
||||
!error
|
||||
? `${formDescriptionId}`
|
||||
: `${formDescriptionId} ${formMessageId}`
|
||||
}
|
||||
aria-invalid={!!error}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
FormControl.displayName = "FormControl"
|
||||
|
||||
const FormDescription = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
React.HTMLAttributes<HTMLParagraphElement>
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { formDescriptionId } = useFormField()
|
||||
|
||||
return (
|
||||
<p
|
||||
ref={ref}
|
||||
id={formDescriptionId}
|
||||
className={cn("text-[0.8rem] text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
})
|
||||
FormDescription.displayName = "FormDescription"
|
||||
|
||||
const FormMessage = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
React.HTMLAttributes<HTMLParagraphElement>
|
||||
>(({ className, children, ...props }, ref) => {
|
||||
const { error, formMessageId } = useFormField()
|
||||
const body = error ? String(error?.message) : children
|
||||
|
||||
if (!body) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<p
|
||||
ref={ref}
|
||||
id={formMessageId}
|
||||
className={cn("text-[0.8rem] font-medium text-destructive", className)}
|
||||
{...props}
|
||||
>
|
||||
{body}
|
||||
</p>
|
||||
)
|
||||
})
|
||||
FormMessage.displayName = "FormMessage"
|
||||
|
||||
export {
|
||||
useFormField,
|
||||
Form,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormMessage,
|
||||
FormField,
|
||||
}
|
||||
22
src/components/ui/input.tsx
Normal file
22
src/components/ui/input.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
|
||||
({ className, type, ...props }, ref) => {
|
||||
return (
|
||||
<input
|
||||
type={type}
|
||||
className={cn(
|
||||
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
Input.displayName = "Input"
|
||||
|
||||
export { Input }
|
||||
26
src/components/ui/label.tsx
Normal file
26
src/components/ui/label.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as LabelPrimitive from "@radix-ui/react-label"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const labelVariants = cva(
|
||||
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
)
|
||||
|
||||
const Label = React.forwardRef<
|
||||
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
|
||||
VariantProps<typeof labelVariants>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<LabelPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(labelVariants(), className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
Label.displayName = LabelPrimitive.Root.displayName
|
||||
|
||||
export { Label }
|
||||
117
src/components/ui/pagination.tsx
Normal file
117
src/components/ui/pagination.tsx
Normal file
@@ -0,0 +1,117 @@
|
||||
import * as React from "react"
|
||||
import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { ButtonProps, buttonVariants } from "@/components/ui/button"
|
||||
|
||||
const Pagination = ({ className, ...props }: React.ComponentProps<"nav">) => (
|
||||
<nav
|
||||
role="navigation"
|
||||
aria-label="pagination"
|
||||
className={cn("mx-auto flex w-full justify-center", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
Pagination.displayName = "Pagination"
|
||||
|
||||
const PaginationContent = React.forwardRef<
|
||||
HTMLUListElement,
|
||||
React.ComponentProps<"ul">
|
||||
>(({ className, ...props }, ref) => (
|
||||
<ul
|
||||
ref={ref}
|
||||
className={cn("flex flex-row items-center gap-1", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
PaginationContent.displayName = "PaginationContent"
|
||||
|
||||
const PaginationItem = React.forwardRef<
|
||||
HTMLLIElement,
|
||||
React.ComponentProps<"li">
|
||||
>(({ className, ...props }, ref) => (
|
||||
<li ref={ref} className={cn("", className)} {...props} />
|
||||
))
|
||||
PaginationItem.displayName = "PaginationItem"
|
||||
|
||||
type PaginationLinkProps = {
|
||||
isActive?: boolean
|
||||
} & Pick<ButtonProps, "size"> &
|
||||
React.ComponentProps<"a">
|
||||
|
||||
const PaginationLink = ({
|
||||
className,
|
||||
isActive,
|
||||
size = "icon",
|
||||
...props
|
||||
}: PaginationLinkProps) => (
|
||||
<a
|
||||
aria-current={isActive ? "page" : undefined}
|
||||
className={cn(
|
||||
buttonVariants({
|
||||
variant: isActive ? "outline" : "ghost",
|
||||
size,
|
||||
}),
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
PaginationLink.displayName = "PaginationLink"
|
||||
|
||||
const PaginationPrevious = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof PaginationLink>) => (
|
||||
<PaginationLink
|
||||
aria-label="Go to previous page"
|
||||
size="default"
|
||||
className={cn("gap-1 pl-2.5", className)}
|
||||
{...props}
|
||||
>
|
||||
<ChevronLeft className="h-4 w-4" />
|
||||
<span>Previous</span>
|
||||
</PaginationLink>
|
||||
)
|
||||
PaginationPrevious.displayName = "PaginationPrevious"
|
||||
|
||||
const PaginationNext = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof PaginationLink>) => (
|
||||
<PaginationLink
|
||||
aria-label="Go to next page"
|
||||
size="default"
|
||||
className={cn("gap-1 pr-2.5", className)}
|
||||
{...props}
|
||||
>
|
||||
<span>Next</span>
|
||||
<ChevronRight className="h-4 w-4" />
|
||||
</PaginationLink>
|
||||
)
|
||||
PaginationNext.displayName = "PaginationNext"
|
||||
|
||||
const PaginationEllipsis = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<"span">) => (
|
||||
<span
|
||||
aria-hidden
|
||||
className={cn("flex h-9 w-9 items-center justify-center", className)}
|
||||
{...props}
|
||||
>
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
<span className="sr-only">More pages</span>
|
||||
</span>
|
||||
)
|
||||
PaginationEllipsis.displayName = "PaginationEllipsis"
|
||||
|
||||
export {
|
||||
Pagination,
|
||||
PaginationContent,
|
||||
PaginationLink,
|
||||
PaginationItem,
|
||||
PaginationPrevious,
|
||||
PaginationNext,
|
||||
PaginationEllipsis,
|
||||
}
|
||||
33
src/components/ui/popover.tsx
Normal file
33
src/components/ui/popover.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as PopoverPrimitive from "@radix-ui/react-popover"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Popover = PopoverPrimitive.Root
|
||||
|
||||
const PopoverTrigger = PopoverPrimitive.Trigger
|
||||
|
||||
const PopoverAnchor = PopoverPrimitive.Anchor
|
||||
|
||||
const PopoverContent = React.forwardRef<
|
||||
React.ElementRef<typeof PopoverPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
|
||||
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
|
||||
<PopoverPrimitive.Portal>
|
||||
<PopoverPrimitive.Content
|
||||
ref={ref}
|
||||
align={align}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</PopoverPrimitive.Portal>
|
||||
))
|
||||
PopoverContent.displayName = PopoverPrimitive.Content.displayName
|
||||
|
||||
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }
|
||||
48
src/components/ui/scroll-area.tsx
Normal file
48
src/components/ui/scroll-area.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const ScrollArea = React.forwardRef<
|
||||
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<ScrollAreaPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn("relative overflow-hidden", className)}
|
||||
{...props}
|
||||
>
|
||||
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
|
||||
{children}
|
||||
</ScrollAreaPrimitive.Viewport>
|
||||
<ScrollBar />
|
||||
<ScrollAreaPrimitive.Corner />
|
||||
</ScrollAreaPrimitive.Root>
|
||||
))
|
||||
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName
|
||||
|
||||
const ScrollBar = React.forwardRef<
|
||||
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
|
||||
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||
>(({ className, orientation = "vertical", ...props }, ref) => (
|
||||
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
||||
ref={ref}
|
||||
orientation={orientation}
|
||||
className={cn(
|
||||
"flex touch-none select-none transition-colors",
|
||||
orientation === "vertical" &&
|
||||
"h-full w-2.5 border-l border-l-transparent p-[1px]",
|
||||
orientation === "horizontal" &&
|
||||
"h-2.5 flex-col border-t border-t-transparent p-[1px]",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
|
||||
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||
))
|
||||
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName
|
||||
|
||||
export { ScrollArea, ScrollBar }
|
||||
29
src/components/ui/switch.tsx
Normal file
29
src/components/ui/switch.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as SwitchPrimitives from "@radix-ui/react-switch"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Switch = React.forwardRef<
|
||||
React.ElementRef<typeof SwitchPrimitives.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SwitchPrimitives.Root
|
||||
className={cn(
|
||||
"peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
>
|
||||
<SwitchPrimitives.Thumb
|
||||
className={cn(
|
||||
"pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0"
|
||||
)}
|
||||
/>
|
||||
</SwitchPrimitives.Root>
|
||||
))
|
||||
Switch.displayName = SwitchPrimitives.Root.displayName
|
||||
|
||||
export { Switch }
|
||||
120
src/components/ui/table.tsx
Normal file
120
src/components/ui/table.tsx
Normal file
@@ -0,0 +1,120 @@
|
||||
import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const Table = React.forwardRef<
|
||||
HTMLTableElement,
|
||||
React.HTMLAttributes<HTMLTableElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div className="relative w-full overflow-auto">
|
||||
<table
|
||||
ref={ref}
|
||||
className={cn("w-full caption-bottom text-sm", className)}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
Table.displayName = "Table"
|
||||
|
||||
const TableHeader = React.forwardRef<
|
||||
HTMLTableSectionElement,
|
||||
React.HTMLAttributes<HTMLTableSectionElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<thead ref={ref} className={cn("[&_tr]:border-b", className)} {...props} />
|
||||
))
|
||||
TableHeader.displayName = "TableHeader"
|
||||
|
||||
const TableBody = React.forwardRef<
|
||||
HTMLTableSectionElement,
|
||||
React.HTMLAttributes<HTMLTableSectionElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<tbody
|
||||
ref={ref}
|
||||
className={cn("[&_tr:last-child]:border-0", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TableBody.displayName = "TableBody"
|
||||
|
||||
const TableFooter = React.forwardRef<
|
||||
HTMLTableSectionElement,
|
||||
React.HTMLAttributes<HTMLTableSectionElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<tfoot
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TableFooter.displayName = "TableFooter"
|
||||
|
||||
const TableRow = React.forwardRef<
|
||||
HTMLTableRowElement,
|
||||
React.HTMLAttributes<HTMLTableRowElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<tr
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TableRow.displayName = "TableRow"
|
||||
|
||||
const TableHead = React.forwardRef<
|
||||
HTMLTableCellElement,
|
||||
React.ThHTMLAttributes<HTMLTableCellElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<th
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"h-10 px-2 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TableHead.displayName = "TableHead"
|
||||
|
||||
const TableCell = React.forwardRef<
|
||||
HTMLTableCellElement,
|
||||
React.TdHTMLAttributes<HTMLTableCellElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<td
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TableCell.displayName = "TableCell"
|
||||
|
||||
const TableCaption = React.forwardRef<
|
||||
HTMLTableCaptionElement,
|
||||
React.HTMLAttributes<HTMLTableCaptionElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<caption
|
||||
ref={ref}
|
||||
className={cn("mt-4 text-sm text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
TableCaption.displayName = "TableCaption"
|
||||
|
||||
export {
|
||||
Table,
|
||||
TableHeader,
|
||||
TableBody,
|
||||
TableFooter,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TableCell,
|
||||
TableCaption,
|
||||
}
|
||||
78
src/lib/renderZodValidation.ts
Normal file
78
src/lib/renderZodValidation.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
"use client";
|
||||
import * as z from "zod";
|
||||
import { ZodDecimal } from "./zodDecimal";
|
||||
|
||||
function convertApiValidationToZodValidation(apiValidation: any) {
|
||||
let zodValidation: any = {};
|
||||
Object.entries(apiValidation).forEach(([key, value]: any) => {
|
||||
const fieldType: String = value.fieldType || "string";
|
||||
const required = value.required || false;
|
||||
if (fieldType === "string") {
|
||||
zodValidation[key] = required
|
||||
? z
|
||||
.string()
|
||||
.min(1)
|
||||
.refine((val) => val !== "" || val !== null)
|
||||
: z
|
||||
.string()
|
||||
.min(1)
|
||||
.optional()
|
||||
.refine((val) => val !== "" || val !== null);
|
||||
} else if (fieldType === "integer") {
|
||||
zodValidation[key] = required
|
||||
? z.preprocess((value) => {
|
||||
try {
|
||||
const parsedValue = Number(value);
|
||||
return isNaN(parsedValue) ? undefined : parsedValue;
|
||||
} catch (error) {
|
||||
return undefined;
|
||||
}
|
||||
}, z.number().min(1))
|
||||
: z.preprocess((value) => {
|
||||
try {
|
||||
const parsedValue = Number(value);
|
||||
return isNaN(parsedValue) ? undefined : parsedValue;
|
||||
} catch (error) {
|
||||
return undefined;
|
||||
}
|
||||
}, z.number().min(1).optional());
|
||||
} else if (fieldType === "boolean") {
|
||||
zodValidation[key] = required ? z.boolean() : z.boolean().optional();
|
||||
} else if (fieldType === "datetime") {
|
||||
zodValidation[key] = required ? z.date() : z.date().optional();
|
||||
} else if (fieldType === "float") {
|
||||
zodValidation[key] = required
|
||||
? ZodDecimal.create({ coerce: true })
|
||||
: ZodDecimal.create({ coerce: true }).optional();
|
||||
}
|
||||
});
|
||||
const validSchemaZod = z.object({
|
||||
...zodValidation,
|
||||
});
|
||||
return {
|
||||
validSchemaZod: validSchemaZod,
|
||||
zodValidation: zodValidation,
|
||||
apiValidation: apiValidation,
|
||||
};
|
||||
}
|
||||
|
||||
function retrieveDataWhichHaveValidation(data: any, apiValidation: any) {
|
||||
const apiValidated = apiValidation?.validated || {};
|
||||
Object.entries(apiValidated).forEach(([key, value]: any) => {
|
||||
const fieldType: String = value.fieldType || "string";
|
||||
const required = value.required || false;
|
||||
if (fieldType === "string") {
|
||||
data[key] = required ? data[key] : data[key] || "";
|
||||
} else if (fieldType === "integer") {
|
||||
data[key] = required ? data[key] : data[key] || 0;
|
||||
} else if (fieldType === "boolean") {
|
||||
data[key] = required ? data[key] : data[key] || false;
|
||||
} else if (fieldType === "datetime") {
|
||||
data[key] = required ? data[key] : new Date(data[key]) || "";
|
||||
} else if (fieldType === "float") {
|
||||
data[key] = required ? data[key] : data[key] || 0.0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export { convertApiValidationToZodValidation, retrieveDataWhichHaveValidation };
|
||||
6
src/lib/utils.ts
Normal file
6
src/lib/utils.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { clsx, type ClassValue } from "clsx"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
306
src/lib/zodDecimal.ts
Normal file
306
src/lib/zodDecimal.ts
Normal file
@@ -0,0 +1,306 @@
|
||||
import {
|
||||
INVALID,
|
||||
ParseContext,
|
||||
ParseInput,
|
||||
ParseReturnType,
|
||||
ParseStatus,
|
||||
RawCreateParams,
|
||||
ZodIssueCode,
|
||||
ZodParsedType,
|
||||
ZodType,
|
||||
ZodTypeDef,
|
||||
addIssueToContext,
|
||||
} from "zod";
|
||||
|
||||
export type ZodDecimalCheck =
|
||||
| { kind: "precision"; value: number; message?: string }
|
||||
| { kind: "wholeNumber"; value: number; message?: string }
|
||||
| { kind: "min"; value: number; inclusive: boolean; message?: string }
|
||||
| { kind: "max"; value: number; inclusive: boolean; message?: string }
|
||||
| { kind: "finite"; message?: string };
|
||||
|
||||
const zodDecimalKind = "ZodDecimal";
|
||||
|
||||
export interface ZodDecimalDef extends ZodTypeDef {
|
||||
checks: ZodDecimalCheck[];
|
||||
typeName: typeof zodDecimalKind;
|
||||
coerce: boolean;
|
||||
}
|
||||
|
||||
const precisionRegex = /(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export class ZodDecimal extends ZodType<number, ZodDecimalDef, any> {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
_parse(input: ParseInput): ParseReturnType<number> {
|
||||
// detect decimal js object
|
||||
if (
|
||||
input.data !== null &&
|
||||
typeof input.data === "object" &&
|
||||
"toNumber" in input.data
|
||||
) {
|
||||
input.data = input.data.toNumber();
|
||||
}
|
||||
if (this._def.coerce) {
|
||||
input.data = Number(input.data);
|
||||
}
|
||||
|
||||
const parsedType = this._getType(input);
|
||||
if (parsedType !== ZodParsedType.number) {
|
||||
const ctx = this._getOrReturnCtx(input);
|
||||
addIssueToContext(ctx, {
|
||||
code: ZodIssueCode.invalid_type,
|
||||
expected: ZodParsedType.number,
|
||||
received: ctx.parsedType,
|
||||
});
|
||||
return INVALID;
|
||||
}
|
||||
|
||||
let ctx: undefined | ParseContext = undefined;
|
||||
const status = new ParseStatus();
|
||||
|
||||
for (const check of this._def.checks) {
|
||||
if (check.kind === "precision") {
|
||||
const parts = input.data.toString().match(precisionRegex);
|
||||
const decimals = Math.max(
|
||||
(parts[1] ? parts[1].length : 0) -
|
||||
(parts[2] ? parseInt(parts[2], 10) : 0),
|
||||
0
|
||||
);
|
||||
if (decimals > check.value) {
|
||||
ctx = this._getOrReturnCtx(input, ctx);
|
||||
addIssueToContext(ctx, {
|
||||
code: ZodIssueCode.custom,
|
||||
message: check.message,
|
||||
params: {
|
||||
precision: check.value,
|
||||
},
|
||||
});
|
||||
status.dirty();
|
||||
}
|
||||
} else if (check.kind === "wholeNumber") {
|
||||
const wholeNumber = input.data.toString().split(".")[0];
|
||||
const tooLong = wholeNumber.length > check.value;
|
||||
|
||||
if (tooLong) {
|
||||
ctx = this._getOrReturnCtx(input, ctx);
|
||||
addIssueToContext(ctx, {
|
||||
code: ZodIssueCode.custom,
|
||||
message: check.message,
|
||||
params: {
|
||||
wholeNumber: check.value,
|
||||
},
|
||||
});
|
||||
status.dirty();
|
||||
}
|
||||
} else if (check.kind === "min") {
|
||||
const tooSmall = check.inclusive
|
||||
? input.data < check.value
|
||||
: input.data <= check.value;
|
||||
if (tooSmall) {
|
||||
ctx = this._getOrReturnCtx(input, ctx);
|
||||
addIssueToContext(ctx, {
|
||||
code: ZodIssueCode.too_small,
|
||||
minimum: check.value,
|
||||
type: "number",
|
||||
inclusive: check.inclusive,
|
||||
exact: false,
|
||||
message: check.message,
|
||||
});
|
||||
status.dirty();
|
||||
}
|
||||
} else if (check.kind === "max") {
|
||||
const tooBig = check.inclusive
|
||||
? input.data > check.value
|
||||
: input.data >= check.value;
|
||||
if (tooBig) {
|
||||
ctx = this._getOrReturnCtx(input, ctx);
|
||||
addIssueToContext(ctx, {
|
||||
code: ZodIssueCode.too_big,
|
||||
maximum: check.value,
|
||||
type: "number",
|
||||
inclusive: check.inclusive,
|
||||
exact: false,
|
||||
message: check.message,
|
||||
});
|
||||
status.dirty();
|
||||
}
|
||||
} else if (check.kind === "finite") {
|
||||
if (!Number.isFinite(input.data)) {
|
||||
ctx = this._getOrReturnCtx(input, ctx);
|
||||
addIssueToContext(ctx, {
|
||||
code: ZodIssueCode.not_finite,
|
||||
message: check.message,
|
||||
});
|
||||
status.dirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { status: status.value, value: input.data };
|
||||
}
|
||||
|
||||
static create = (
|
||||
params?: RawCreateParams & { coerce?: true }
|
||||
): ZodDecimal => {
|
||||
return new ZodDecimal({
|
||||
checks: [],
|
||||
typeName: zodDecimalKind,
|
||||
coerce: params?.coerce ?? false,
|
||||
});
|
||||
};
|
||||
|
||||
protected setLimit(
|
||||
kind: "min" | "max",
|
||||
value: number,
|
||||
inclusive: boolean,
|
||||
message?: string
|
||||
): ZodDecimal {
|
||||
return new ZodDecimal({
|
||||
...this._def,
|
||||
checks: [
|
||||
...this._def.checks,
|
||||
{
|
||||
kind,
|
||||
value,
|
||||
inclusive,
|
||||
message,
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
_addCheck(check: ZodDecimalCheck): ZodDecimal {
|
||||
return new ZodDecimal({
|
||||
...this._def,
|
||||
checks: [...this._def.checks, check],
|
||||
});
|
||||
}
|
||||
|
||||
lte(value: number, message?: string): ZodDecimal {
|
||||
return this.setLimit("max", value, true, message);
|
||||
}
|
||||
|
||||
lt(value: number, message?: string): ZodDecimal {
|
||||
return this.setLimit("max", value, false, message);
|
||||
}
|
||||
max = this.lte;
|
||||
|
||||
gt(value: number, message?: string): ZodDecimal {
|
||||
return this.setLimit("min", value, false, message);
|
||||
}
|
||||
gte(value: number, message?: string): ZodDecimal {
|
||||
return this.setLimit("min", value, true, message);
|
||||
}
|
||||
|
||||
min = this.gte;
|
||||
|
||||
precision(value: number, message?: string): ZodDecimal {
|
||||
return this._addCheck({
|
||||
kind: "precision",
|
||||
value,
|
||||
message,
|
||||
});
|
||||
}
|
||||
wholeNumber(value: number, message?: string): ZodDecimal {
|
||||
return this._addCheck({
|
||||
kind: "wholeNumber",
|
||||
value,
|
||||
message,
|
||||
});
|
||||
}
|
||||
|
||||
get minValue() {
|
||||
let min: number | null = null;
|
||||
for (const ch of this._def.checks) {
|
||||
if (ch.kind === "min") {
|
||||
if (min === null || ch.value > min) min = ch.value;
|
||||
}
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
get maxValue() {
|
||||
let max: number | null = null;
|
||||
for (const ch of this._def.checks) {
|
||||
if (ch.kind === "max") {
|
||||
if (max === null || ch.value < max) max = ch.value;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
positive(message?: string) {
|
||||
return this._addCheck({
|
||||
kind: "min",
|
||||
value: 0,
|
||||
inclusive: false,
|
||||
message,
|
||||
});
|
||||
}
|
||||
|
||||
negative(message?: string) {
|
||||
return this._addCheck({
|
||||
kind: "max",
|
||||
value: 0,
|
||||
inclusive: false,
|
||||
message,
|
||||
});
|
||||
}
|
||||
|
||||
nonpositive(message?: string) {
|
||||
return this._addCheck({
|
||||
kind: "max",
|
||||
value: 0,
|
||||
inclusive: true,
|
||||
message,
|
||||
});
|
||||
}
|
||||
|
||||
nonnegative(message?: string) {
|
||||
return this._addCheck({
|
||||
kind: "min",
|
||||
value: 0,
|
||||
inclusive: true,
|
||||
message,
|
||||
});
|
||||
}
|
||||
|
||||
finite(message?: string) {
|
||||
return this._addCheck({
|
||||
kind: "finite",
|
||||
message,
|
||||
});
|
||||
}
|
||||
|
||||
safe(message?: string) {
|
||||
return this._addCheck({
|
||||
kind: "min",
|
||||
inclusive: true,
|
||||
value: Number.MIN_SAFE_INTEGER,
|
||||
message,
|
||||
})._addCheck({
|
||||
kind: "max",
|
||||
inclusive: true,
|
||||
value: Number.MAX_SAFE_INTEGER,
|
||||
message,
|
||||
});
|
||||
}
|
||||
|
||||
get isFinite() {
|
||||
let max: number | null = null,
|
||||
min: number | null = null;
|
||||
for (const ch of this._def.checks) {
|
||||
if (ch.kind === "finite") {
|
||||
return true;
|
||||
} else if (ch.kind === "min") {
|
||||
if (min === null || ch.value > min) min = ch.value;
|
||||
} else if (ch.kind === "max") {
|
||||
if (max === null || ch.value < max) max = ch.value;
|
||||
}
|
||||
}
|
||||
return Number.isFinite(min) && Number.isFinite(max);
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
export const zodDecimal = ZodDecimal.create;
|
||||
34
src/pages/LoginSelectEmployee/page.tsx
Normal file
34
src/pages/LoginSelectEmployee/page.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
"use server";
|
||||
import React from "react";
|
||||
import SelectEmployeeFrom from "./selectFrom";
|
||||
import { redirect } from "next/navigation";
|
||||
// import LeftSidePanel from "@/components/login/leftsidepanel";
|
||||
{
|
||||
/* <LeftSidePanel textLabel="Evyos Yönetim Modülüne hoşgeldiniz" /> */
|
||||
}
|
||||
|
||||
interface InterfaceLoginSelectEmployee {
|
||||
companyList: any;
|
||||
}
|
||||
|
||||
const LoginSelectEmployeeCard: React.FC<InterfaceLoginSelectEmployee> = async (
|
||||
companyList: any
|
||||
) => {
|
||||
if (!companyList) {
|
||||
redirect("/login/email");
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<div className="min-h-full min-w-full">
|
||||
<h1 className="mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900">
|
||||
Şirket Seçimi Yapınız
|
||||
</h1>
|
||||
<div>
|
||||
<SelectEmployeeFrom companyList={companyList?.companyList} />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoginSelectEmployeeCard;
|
||||
70
src/pages/LoginSelectEmployee/selectFrom.tsx
Normal file
70
src/pages/LoginSelectEmployee/selectFrom.tsx
Normal file
@@ -0,0 +1,70 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import Image from "next/image";
|
||||
import { loginSelectEmployee } from "@/apicalls/login/login";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
interface InterfaceSelectEmployeeFrom {
|
||||
companyList: any;
|
||||
}
|
||||
|
||||
const SelectEmployeeFrom: React.FC<InterfaceSelectEmployeeFrom> = ({
|
||||
companyList,
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
console.log("companyList", companyList);
|
||||
function onClick(data: any) {
|
||||
loginSelectEmployee({ company_uu_id: data?.uu_id })
|
||||
.then((responseData: any) => {
|
||||
if (responseData?.completed) {
|
||||
router.push("/dashboard");
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="sm:grid sm:grid-cols-3 sm:gap-4">
|
||||
{companyList.map((data: any) => (
|
||||
<div className="flex" key={data.uu_id}>
|
||||
<div
|
||||
className="flex sm:h-56 hover:bg-white bg-emerald-800 m-3 ring-1 shadow-xl ring-emerald-700 p-3 h-64 rounded-2xl"
|
||||
key={data.uu_id}
|
||||
onClick={() => onClick(data)}
|
||||
>
|
||||
<div className="lg:w-1/4">
|
||||
<Image
|
||||
src={"/green-house.webp"}
|
||||
alt={`Evyos ${data.uu_id}`}
|
||||
className=" w-full h-full object-cover"
|
||||
width={300}
|
||||
height={300}
|
||||
/>
|
||||
</div>
|
||||
<div className="lg:w-3/4 m-5">
|
||||
<h2 className="text-lg font-bold mb-2">UUID : {data.uu_id}</h2>
|
||||
<h2 className="text-lg font-bold mb-2">
|
||||
Şirket Unvanı : {data.public_name}
|
||||
</h2>
|
||||
<h2 className="text-lg font-bold mb-2">
|
||||
Şirket Tipi Name : {data.company_type}
|
||||
</h2>
|
||||
<h2 className="text-lg font-bold mb-2">
|
||||
Adres :{" "}
|
||||
{data.company_address
|
||||
? data.company_address
|
||||
: "Tanımlı Değil"}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelectEmployeeFrom;
|
||||
30
src/pages/LoginSelectOccupant/page.tsx
Normal file
30
src/pages/LoginSelectOccupant/page.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
"use server";
|
||||
import React from "react";
|
||||
import SelectOccupantFrom from "./selectFrom";
|
||||
// import LeftSidePanel from "@/components/login/leftsidepanel";
|
||||
{
|
||||
/* <LeftSidePanel textLabel="Evyos Yönetim Modülüne hoşgeldiniz. Lütfen mail adresinizi ve şifreniz ile giriş yapınız." /> */
|
||||
}
|
||||
|
||||
interface interfaceLoginSelectOccupant {
|
||||
availableOccupants: any;
|
||||
}
|
||||
|
||||
const LoginSelectOccupantCard: React.FC<interfaceLoginSelectOccupant> = async ({
|
||||
availableOccupants,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<div className="min-h-full min-w-full">
|
||||
<h1 className="mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900">
|
||||
Görev Seçimi Yapınız
|
||||
</h1>
|
||||
<div>
|
||||
<SelectOccupantFrom availableOccupants={availableOccupants} />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoginSelectOccupantCard;
|
||||
154
src/pages/LoginSelectOccupant/selectFrom.tsx
Normal file
154
src/pages/LoginSelectOccupant/selectFrom.tsx
Normal file
@@ -0,0 +1,154 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { loginSelectOccupant } from "@/apicalls/login/login";
|
||||
import Image from "next/image";
|
||||
|
||||
interface Building {
|
||||
build_uu_id: string;
|
||||
build_name: string;
|
||||
build_no: string;
|
||||
occupants: Array<any>;
|
||||
}
|
||||
|
||||
interface InterfaceSelectOccupanyFrom {
|
||||
availableOccupants: Record<string, Building>;
|
||||
}
|
||||
|
||||
const SelectOccupantFrom: React.FC<InterfaceSelectOccupanyFrom> = ({
|
||||
availableOccupants,
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
const [activeBuildingList, setActiveBuildingList] = React.useState<
|
||||
Building[]
|
||||
>([]);
|
||||
const [activeOccupantList, setActiveOccupantList] = React.useState<any[]>([]);
|
||||
const [isBuildingSelected, setIsBuildingSelected] = React.useState(false);
|
||||
const [selectedBuilding, setSelectedBuilding] = React.useState("");
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!isBuildingSelected) {
|
||||
const uniqueBuildings = Object.values(availableOccupants).map(
|
||||
(value) => ({
|
||||
build_uu_id: value.build_uu_id,
|
||||
build_name: value.build_name,
|
||||
build_no: value.build_no,
|
||||
occupants: value.occupants,
|
||||
})
|
||||
);
|
||||
setActiveBuildingList(uniqueBuildings);
|
||||
}
|
||||
}, [availableOccupants, isBuildingSelected]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (isBuildingSelected && selectedBuilding) {
|
||||
const selectedOccupants =
|
||||
Object.values(availableOccupants).find(
|
||||
(value) => value.build_uu_id === selectedBuilding
|
||||
)?.occupants || [];
|
||||
setActiveOccupantList(selectedOccupants);
|
||||
}
|
||||
}, [isBuildingSelected, selectedBuilding, availableOccupants]);
|
||||
|
||||
const onClickBuild = (data: Building) => {
|
||||
setSelectedBuilding(data.build_uu_id);
|
||||
setIsBuildingSelected(true);
|
||||
};
|
||||
|
||||
const onClick = (data: any) => {
|
||||
loginSelectOccupant({
|
||||
build_part_uu_id: data?.part_uu_id,
|
||||
occupant_uu_id: data?.uu_id,
|
||||
selectedBuilding: selectedBuilding,
|
||||
})
|
||||
.then((responseData: { completed: boolean }) => {
|
||||
console.log("responseData", responseData);
|
||||
console.log("responseData.completed", responseData?.completed);
|
||||
if (responseData?.completed) {
|
||||
router.replace("/dashboard");
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Login error:", error);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{!isBuildingSelected ? (
|
||||
<div className="3xl:grid 3xl:grid-cols-3 3xl:gap-4">
|
||||
{activeBuildingList.map((data: any) => (
|
||||
<div
|
||||
className="flex sm:h-56 hover:bg-white bg-emerald-800 m-3 ring-1 shadow-xl ring-emerald-700 p-3 h-64 rounded-2xl"
|
||||
onClick={() => onClickBuild(data)}
|
||||
key={data.build_uu_id}
|
||||
>
|
||||
<div className="w-1/4">
|
||||
<Image
|
||||
src={"/green-house.webp"}
|
||||
alt={`Evyos ${data.build_uu_id}`}
|
||||
className=" w-full h-full object-cover"
|
||||
width={300}
|
||||
height={300}
|
||||
/>
|
||||
</div>
|
||||
<div className="w-3/4 m-5">
|
||||
<h2 className="text-lg font-bold mb-2">
|
||||
UUID : {data.build_uu_id}
|
||||
</h2>
|
||||
<h2 className="text-lg font-bold mb-2">
|
||||
Bina : {data.build_name}
|
||||
</h2>
|
||||
<h2 className="text-lg font-bold mb-2">
|
||||
Bina No : {data.build_no}
|
||||
</h2>
|
||||
{/* <h2 className="text-lg font-bold mb-2">
|
||||
Adres :{" "}
|
||||
{data.company_address
|
||||
? data.company_address
|
||||
: "Tanımlı Değil"}
|
||||
</h2> */}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="3xl:grid 3xl:grid-cols-3 3xl:gap-4">
|
||||
{activeOccupantList.map((data: any) => (
|
||||
<div
|
||||
className="flex sm:h-56 hover:bg-white bg-emerald-800 m-3 ring-1 shadow-xl ring-emerald-700 p-3 h-64 rounded-2xl"
|
||||
key={`${data.part_uu_id}-${data.uu_id}`}
|
||||
onClick={() => onClick(data)}
|
||||
>
|
||||
<div className="w-1/4">
|
||||
<Image
|
||||
src={"/green-house.webp"}
|
||||
alt={`Evyos ${data.part_uu_id}`}
|
||||
className=" w-full h-full object-cover"
|
||||
width={300}
|
||||
height={300}
|
||||
/>
|
||||
</div>
|
||||
<div className="w-3/4 m-5">
|
||||
<h2 className="text-lg font-bold mb-2">
|
||||
UUID : {data.part_uu_id}
|
||||
</h2>
|
||||
<h2 className="text-lg font-bold mb-2">
|
||||
Bina : {data.part_name}
|
||||
</h2>
|
||||
<h2 className="text-lg font-bold mb-2">
|
||||
Daire Kat : {data.part_level}
|
||||
</h2>
|
||||
<h2 className="text-lg font-bold mb-2">
|
||||
Giriş Tipi : {data.code} - {data.description}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelectOccupantFrom;
|
||||
23
src/pages/LoginViaEmail/page.tsx
Normal file
23
src/pages/LoginViaEmail/page.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import SignInForm from "./singInForm";
|
||||
import LeftSidePanel from "@/components/login/leftsidepanel";
|
||||
|
||||
const LoginWithEmail: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
<div className="absolute top-0 left-0 min-w-full min-h-full">
|
||||
<div className="mx-auto max-w-screen-2xl p-4 md:p-6 2xl:p-10">
|
||||
<div className="rounded-sm border border-stroke bg-white shadow-default dark:border-strokedark dark:bg-boxdark">
|
||||
<div className="flex flex-wrap items-center">
|
||||
<LeftSidePanel textLabel="Evyos Yönetim Modülüne hoşgeldiniz. Lütfen mail adresinizi ve şifreniz ile giriş yapınız." />
|
||||
<SignInForm />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoginWithEmail;
|
||||
17
src/pages/LoginViaEmail/schema.ts
Normal file
17
src/pages/LoginViaEmail/schema.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import * as z from "zod";
|
||||
|
||||
const loginSchema = z.object({
|
||||
loginEmailInput: z
|
||||
.string()
|
||||
.min(4, { message: "Email adresi minimum 4 karaterden oluşmalıdır" })
|
||||
.email("Geçerli bir mail adresi giriniz")
|
||||
.default(""),
|
||||
loginPassword: z
|
||||
.string()
|
||||
.min(5, { message: "Şifre 6 karakterden az olamaz" })
|
||||
.default(""),
|
||||
loginRememberMe: z.boolean().optional().default(false),
|
||||
});
|
||||
|
||||
export type LoginFormSchema = z.infer<typeof loginSchema>;
|
||||
export { loginSchema };
|
||||
154
src/pages/LoginViaEmail/singInForm.tsx
Normal file
154
src/pages/LoginViaEmail/singInForm.tsx
Normal file
@@ -0,0 +1,154 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import { Eye, EyeOff, Mail } from "lucide-react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { loginViaAccessKeys } from "@/apicalls/login/login";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
|
||||
import { loginSchema, LoginFormSchema } from "./schema";
|
||||
import {
|
||||
GoogleButton,
|
||||
LoginButton,
|
||||
ChangeSignTypeButton,
|
||||
} from "@/components/login/buttons";
|
||||
|
||||
const SignInForm: React.FC = () => {
|
||||
const router = useRouter();
|
||||
const [showPassword, setShowPassword] = React.useState(false);
|
||||
|
||||
const form = useForm<LoginFormSchema>({
|
||||
resolver: zodResolver(loginSchema),
|
||||
});
|
||||
|
||||
function onSubmit(values: LoginFormSchema) {
|
||||
loginViaAccessKeys({
|
||||
domain: "evyos.com.tr",
|
||||
accessKey: values.loginEmailInput,
|
||||
password: values.loginPassword,
|
||||
rememberMe: values.loginRememberMe,
|
||||
})
|
||||
.then((res: any) => {
|
||||
console.log("res", res);
|
||||
if (res?.completed) {
|
||||
setTimeout(() => {
|
||||
router.push("/login/select");
|
||||
}, 1000);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("error", error);
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-full border-stroke dark:border-strokedark xl:w-1/2 xl:border-l-2">
|
||||
<div className="w-full p-4 sm:p-12.5 xl:p-17.5">
|
||||
<h2 className="my-9 text-center text-2xl font-bold text-black dark:text-white sm:text-title-xl2">
|
||||
Mail ile Giriş Yapın
|
||||
</h2>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
className="space-y-5 max-w-3xl mx-auto py-10"
|
||||
>
|
||||
<div className="mb-4">
|
||||
<label className="mb-2.5 block font-medium text-black dark:text-white">
|
||||
Email
|
||||
</label>
|
||||
<div className="relative">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="loginEmailInput"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<input
|
||||
type="email"
|
||||
placeholder="example@example.net"
|
||||
className="w-full rounded-lg border border-stroke bg-transparent py-4 pl-6 pr-10 text-black outline-none focus:border-primary focus-visible:shadow-none dark:border-form-strokedark dark:bg-form-input dark:text-white dark:focus:border-primary"
|
||||
{...field}
|
||||
value={field.value || ""}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<span className="absolute right-4 top-4">
|
||||
<Mail />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-6">
|
||||
<label className="mb-2.5 block font-medium text-black dark:text-white">
|
||||
Password
|
||||
</label>
|
||||
<div className="relative">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="loginPassword"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<input
|
||||
type={showPassword ? "text" : "password"}
|
||||
placeholder="Şifre giriniz"
|
||||
className="w-full rounded-lg border border-stroke bg-transparent py-4 pl-6 pr-10 text-black outline-none focus:border-primary focus-visible:shadow-none dark:border-form-strokedark dark:bg-form-input dark:text-white dark:focus:border-primary"
|
||||
{...field}
|
||||
value={field.value || ""}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<span
|
||||
className="absolute right-4 top-4"
|
||||
onClick={() => setShowPassword(!showPassword)}
|
||||
>
|
||||
{!showPassword ? <Eye /> : <EyeOff />}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="loginRememberMe"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-row items-center justify-between rounded-lg border p-4">
|
||||
<div className="space-y-0.5">
|
||||
<FormLabel className="text-lg">Beni Hatırla</FormLabel>
|
||||
</div>
|
||||
<FormControl>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
aria-readonly
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<LoginButton />
|
||||
<GoogleButton />
|
||||
</form>
|
||||
</Form>
|
||||
<ChangeSignTypeButton buttonType="phone" />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SignInForm;
|
||||
23
src/pages/LoginViaPhone/page.tsx
Normal file
23
src/pages/LoginViaPhone/page.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import SignPhoneInForm from "./singInForm";
|
||||
import LeftSidePanel from "@/components/login/leftsidepanel";
|
||||
|
||||
const LoginWithPhone: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
<div className="absolute top-0 left-0 min-w-full min-h-full">
|
||||
<div className="mx-auto max-w-screen-2xl p-4 md:p-6 2xl:p-10">
|
||||
<div className="rounded-sm border border-stroke bg-white shadow-default dark:border-strokedark dark:bg-boxdark">
|
||||
<div className="flex flex-wrap items-center">
|
||||
<LeftSidePanel textLabel="Evyos Yönetim Modülüne hoşgeldiniz. Lütfen telefon ve şifreniz ile giriş yapınız." />
|
||||
<SignPhoneInForm />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoginWithPhone;
|
||||
17
src/pages/LoginViaPhone/schema.ts
Normal file
17
src/pages/LoginViaPhone/schema.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import * as z from "zod";
|
||||
|
||||
const loginPhoneSchema = z.object({
|
||||
loginPhone: z
|
||||
.string()
|
||||
.min(10, { message: "Telefon numarası 10 karakterden az olamaz" })
|
||||
.max(14, { message: "Telefon numarası 14 karakterden fazla olamaz" })
|
||||
.default(""),
|
||||
loginPassword: z
|
||||
.string()
|
||||
.min(5, { message: "Şifre 6 karakterden az olamaz" })
|
||||
.default(""),
|
||||
loginRememberMe: z.boolean().optional().default(false),
|
||||
});
|
||||
|
||||
export type LoginPhoneFormSchema = z.infer<typeof loginPhoneSchema>;
|
||||
export { loginPhoneSchema };
|
||||
153
src/pages/LoginViaPhone/singInForm.tsx
Normal file
153
src/pages/LoginViaPhone/singInForm.tsx
Normal file
@@ -0,0 +1,153 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import { Eye, EyeOff, Mail } from "lucide-react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { loginViaAccessKeys } from "@/apicalls/login/login";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
|
||||
import { LoginPhoneFormSchema, loginPhoneSchema } from "./schema";
|
||||
import {
|
||||
GoogleButton,
|
||||
LoginButton,
|
||||
ChangeSignTypeButton,
|
||||
} from "@/components/login/buttons";
|
||||
|
||||
const SignPhoneInForm: React.FC = () => {
|
||||
const router = useRouter();
|
||||
const [showPassword, setShowPassword] = React.useState(false);
|
||||
|
||||
const form = useForm<LoginPhoneFormSchema>({
|
||||
resolver: zodResolver(loginPhoneSchema),
|
||||
});
|
||||
|
||||
function onSubmit(values: LoginPhoneFormSchema) {
|
||||
loginViaAccessKeys({
|
||||
domain: "evyos.com.tr",
|
||||
accessKey: values.loginPhone,
|
||||
password: values.loginPassword,
|
||||
rememberMe: values.loginRememberMe,
|
||||
})
|
||||
.then((res: any) => {
|
||||
if (res?.completed) {
|
||||
setTimeout(() => {
|
||||
router.push("/login/select");
|
||||
}, 1000);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("error", error);
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-full border-stroke dark:border-strokedark xl:w-1/2 xl:border-l-2">
|
||||
<div className="w-full p-4 sm:p-12.5 xl:p-17.5">
|
||||
<h2 className="my-9 text-center text-2xl font-bold text-black dark:text-white sm:text-title-xl2">
|
||||
Mail ile Giriş Yapın
|
||||
</h2>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
className="space-y-5 max-w-3xl mx-auto py-10"
|
||||
>
|
||||
<div className="mb-4">
|
||||
<label className="mb-2.5 block font-medium text-black dark:text-white">
|
||||
Email
|
||||
</label>
|
||||
<div className="relative">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="loginPhone"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<input
|
||||
type="email"
|
||||
placeholder="example@example.net"
|
||||
className="w-full rounded-lg border border-stroke bg-transparent py-4 pl-6 pr-10 text-black outline-none focus:border-primary focus-visible:shadow-none dark:border-form-strokedark dark:bg-form-input dark:text-white dark:focus:border-primary"
|
||||
{...field}
|
||||
value={field.value || ""}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<span className="absolute right-4 top-4">
|
||||
<Mail />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-6">
|
||||
<label className="mb-2.5 block font-medium text-black dark:text-white">
|
||||
Password
|
||||
</label>
|
||||
<div className="relative">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="loginPassword"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<input
|
||||
type={showPassword ? "text" : "password"}
|
||||
placeholder="Şifre giriniz"
|
||||
className="w-full rounded-lg border border-stroke bg-transparent py-4 pl-6 pr-10 text-black outline-none focus:border-primary focus-visible:shadow-none dark:border-form-strokedark dark:bg-form-input dark:text-white dark:focus:border-primary"
|
||||
{...field}
|
||||
value={field.value || ""}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<span
|
||||
className="absolute right-4 top-4"
|
||||
onClick={() => setShowPassword(!showPassword)}
|
||||
>
|
||||
{!showPassword ? <Eye /> : <EyeOff />}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="loginRememberMe"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-row items-center justify-between rounded-lg border p-4">
|
||||
<div className="space-y-0.5">
|
||||
<FormLabel className="text-lg">Beni Hatırla</FormLabel>
|
||||
</div>
|
||||
<FormControl>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
aria-readonly
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<LoginButton />
|
||||
<GoogleButton />
|
||||
</form>
|
||||
</Form>
|
||||
<ChangeSignTypeButton buttonType="email" />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SignPhoneInForm;
|
||||
62
tailwind.config.ts
Normal file
62
tailwind.config.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import type { Config } from "tailwindcss";
|
||||
|
||||
export default {
|
||||
darkMode: ["class"],
|
||||
content: [
|
||||
"./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
background: 'hsl(var(--background))',
|
||||
foreground: 'hsl(var(--foreground))',
|
||||
card: {
|
||||
DEFAULT: 'hsl(var(--card))',
|
||||
foreground: 'hsl(var(--card-foreground))'
|
||||
},
|
||||
popover: {
|
||||
DEFAULT: 'hsl(var(--popover))',
|
||||
foreground: 'hsl(var(--popover-foreground))'
|
||||
},
|
||||
primary: {
|
||||
DEFAULT: 'hsl(var(--primary))',
|
||||
foreground: 'hsl(var(--primary-foreground))'
|
||||
},
|
||||
secondary: {
|
||||
DEFAULT: 'hsl(var(--secondary))',
|
||||
foreground: 'hsl(var(--secondary-foreground))'
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: 'hsl(var(--muted))',
|
||||
foreground: 'hsl(var(--muted-foreground))'
|
||||
},
|
||||
accent: {
|
||||
DEFAULT: 'hsl(var(--accent))',
|
||||
foreground: 'hsl(var(--accent-foreground))'
|
||||
},
|
||||
destructive: {
|
||||
DEFAULT: 'hsl(var(--destructive))',
|
||||
foreground: 'hsl(var(--destructive-foreground))'
|
||||
},
|
||||
border: 'hsl(var(--border))',
|
||||
input: 'hsl(var(--input))',
|
||||
ring: 'hsl(var(--ring))',
|
||||
chart: {
|
||||
'1': 'hsl(var(--chart-1))',
|
||||
'2': 'hsl(var(--chart-2))',
|
||||
'3': 'hsl(var(--chart-3))',
|
||||
'4': 'hsl(var(--chart-4))',
|
||||
'5': 'hsl(var(--chart-5))'
|
||||
}
|
||||
},
|
||||
borderRadius: {
|
||||
lg: 'var(--radius)',
|
||||
md: 'calc(var(--radius) - 2px)',
|
||||
sm: 'calc(var(--radius) - 4px)'
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: [require("tailwindcss-animate")],
|
||||
} satisfies Config;
|
||||
29
tsconfig.json
Normal file
29
tsconfig.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2017",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/apicalls/*": ["./apicalls/*"],
|
||||
"@/apimaps/*": ["./apimaps/*"],
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
Reference in New Issue
Block a user