old version placed
This commit is contained in:
parent
08b7ad5c00
commit
00acc8c320
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
|
|
@ -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 };
|
||||
|
|
@ -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 };
|
||||
|
|
@ -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 };
|
||||
|
|
@ -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 };
|
||||
|
|
@ -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 };
|
||||
|
|
@ -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 };
|
||||
|
|
@ -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,
|
||||
};
|
||||
|
|
@ -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 };
|
||||
|
|
@ -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 };
|
||||
|
|
@ -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 };
|
||||
|
|
@ -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 };
|
||||
|
|
@ -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,
|
||||
};
|
||||
|
|
@ -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 };
|
||||
|
|
@ -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 };
|
||||
|
|
@ -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 };
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
const AccesibleAllEndpoints = [
|
||||
"/event/list",
|
||||
"/bind/services/occupant",
|
||||
"/bind/services/employee",
|
||||
];
|
||||
|
||||
const AccesibleSelfEndpoints = ["/event/list"];
|
||||
|
||||
export { AccesibleAllEndpoints, AccesibleSelfEndpoints };
|
||||
|
|
@ -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,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 };
|
||||
|
|
@ -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,0 +1 @@
|
|||
|
||||
|
|
@ -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 };
|
||||
|
|
@ -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,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 };
|
||||
|
|
@ -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,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,
|
||||
};
|
||||
|
|
@ -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,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 };
|
||||
|
|
@ -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 };
|
||||
|
|
@ -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 };
|
||||
|
|
@ -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 };
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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 };
|
||||
|
|
@ -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 };
|
||||
|
|
@ -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 };
|
||||
|
|
@ -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 };
|
||||
|
|
@ -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"
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
/* config options here */
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/** @type {import('postcss-load-config').Config} */
|
||||
const config = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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 |
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
@ -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 };
|
||||
|
|
@ -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;
|
||||
|
|
@ -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 }
|
||||
|
|
@ -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 }
|
||||
|
|
@ -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,
|
||||
}
|
||||
|
|
@ -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 }
|
||||
|
|
@ -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 }
|
||||
|
|
@ -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,
|
||||
}
|
||||
|
|
@ -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 }
|
||||
|
|
@ -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 }
|
||||
|
|
@ -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 }
|
||||
|
|
@ -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,
|
||||
}
|
||||
|
|
@ -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 };
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
import { clsx, type ClassValue } from "clsx"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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 };
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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 };
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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"]
|
||||
}
|
||||
Loading…
Reference in New Issue