fix coolify deploy
This commit is contained in:
1 parent
0ccfb06bf1
commit
a0be12fd6f
79 files changed
+3688
-5008
No files matched your search
@@ -0,0 +1 @@
|
|||||||
|
NEXT_PUBLIC_API_URL=https://lgg-bashgah-api.liara.run
|
||||||
Generated
+22
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="accountSettings">
|
||||||
|
<option name="activeProfile" value="profile:default" />
|
||||||
|
<option name="activeRegion" value="eu-central-1" />
|
||||||
|
<option name="recentlyUsedProfiles">
|
||||||
|
<list>
|
||||||
|
<option value="profile:default" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
<option name="recentlyUsedRegions">
|
||||||
|
<list>
|
||||||
|
<option value="eu-central-1" />
|
||||||
|
<option value="eu-west-1" />
|
||||||
|
<option value="us-east-1" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="explorerToolWindow">
|
||||||
|
<option name="selectedTab" value="Explorer" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
</profile>
|
||||||
|
</component>
|
||||||
Generated
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://ui.shadcn.com/schema.json",
|
||||||
|
"style": "default",
|
||||||
|
"rsc": true,
|
||||||
|
"tsx": true,
|
||||||
|
"tailwind": {
|
||||||
|
"config": "tailwind.config.ts",
|
||||||
|
"css": "src/app/globals.css",
|
||||||
|
"baseColor": "slate",
|
||||||
|
"cssVariables": true,
|
||||||
|
"prefix": ""
|
||||||
|
},
|
||||||
|
"aliases": {
|
||||||
|
"components": "@/components",
|
||||||
|
"utils": "@/lib/utils"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"platform": "next",
|
||||||
|
"app": "admin-mojrian"
|
||||||
|
}
|
||||||
+33
-1
@@ -1,4 +1,36 @@
|
|||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {};
|
const nextConfig = {
|
||||||
|
typescript: {
|
||||||
|
// !! WARN !!
|
||||||
|
// Dangerously allow production builds to successfully complete even if
|
||||||
|
// your project has type errors.
|
||||||
|
// !! WARN !!
|
||||||
|
ignoreBuildErrors: true,
|
||||||
|
},
|
||||||
|
eslint: {
|
||||||
|
// Warning: This allows production builds to successfully complete even if
|
||||||
|
// your project has ESLint errors.
|
||||||
|
ignoreDuringBuilds: true,
|
||||||
|
},
|
||||||
|
images: {
|
||||||
|
remotePatterns: [
|
||||||
|
{
|
||||||
|
protocol: 'https',
|
||||||
|
hostname: 'lgg-bashgah-api.liara.run',
|
||||||
|
port: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
protocol: 'https',
|
||||||
|
hostname: 'mojrian-api.loolegostar.com',
|
||||||
|
port: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
protocol: 'http',
|
||||||
|
hostname: '127.0.0.1',
|
||||||
|
port: '8000'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export default nextConfig;
|
export default nextConfig;
|
||||||
Generated
-4827
File diff suppressed because it is too large.
Load diff
+22
-4
@@ -9,18 +9,36 @@
|
|||||||
"lint": "next lint"
|
"lint": "next lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@hookform/resolvers": "^3.3.4",
|
||||||
|
"@radix-ui/react-checkbox": "^1.0.4",
|
||||||
|
"@radix-ui/react-dialog": "^1.0.5",
|
||||||
|
"@radix-ui/react-label": "^2.0.2",
|
||||||
|
"@radix-ui/react-select": "^2.0.0",
|
||||||
|
"@radix-ui/react-slot": "^1.0.2",
|
||||||
|
"@tanstack/react-query": "^5.29.2",
|
||||||
|
"@types/moment-jalaali": "^0.7.9",
|
||||||
|
"axios": "^1.6.8",
|
||||||
|
"class-variance-authority": "^0.7.0",
|
||||||
|
"clsx": "^2.1.0",
|
||||||
|
"lucide-react": "^0.368.0",
|
||||||
|
"moment-jalaali": "^0.10.0",
|
||||||
|
"next": "14.2.1",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
"react-dom": "^18",
|
"react-dom": "^18",
|
||||||
"next": "14.2.1"
|
"react-hook-form": "^7.51.3",
|
||||||
|
"react-icons": "^5.0.1",
|
||||||
|
"tailwind-merge": "^2.2.2",
|
||||||
|
"tailwindcss-animate": "^1.0.7",
|
||||||
|
"zod": "^3.22.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^5",
|
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^18",
|
"@types/react": "^18",
|
||||||
"@types/react-dom": "^18",
|
"@types/react-dom": "^18",
|
||||||
|
"eslint": "^8",
|
||||||
|
"eslint-config-next": "14.2.1",
|
||||||
"postcss": "^8",
|
"postcss": "^8",
|
||||||
"tailwindcss": "^3.4.1",
|
"tailwindcss": "^3.4.1",
|
||||||
"eslint": "^8",
|
"typescript": "^5"
|
||||||
"eslint-config-next": "14.2.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
CREATE TABLE "CUser" (
|
||||||
|
"id" bigint,
|
||||||
|
"mobile" bigint,
|
||||||
|
"name_family" varchar,
|
||||||
|
"step" int,
|
||||||
|
"type" varchar
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "Profile" (
|
||||||
|
"codemeli" bigint,
|
||||||
|
"city" bigint,
|
||||||
|
"address" varchar,
|
||||||
|
"codeposti" int,
|
||||||
|
"ax_mojri" varchar,
|
||||||
|
"ax_meli" varchar,
|
||||||
|
"ax_fani" varchar,
|
||||||
|
"ax_sayer" varchar
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "ProductCategory" (
|
||||||
|
"codemeli" bigint,
|
||||||
|
"city" bigint,
|
||||||
|
"address" varchar,
|
||||||
|
"codeposti" int,
|
||||||
|
"ax_mojri" varchar,
|
||||||
|
"ax_meli" varchar,
|
||||||
|
"ax_fani" varchar,
|
||||||
|
"ax_sayer" varchar
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "follows" (
|
||||||
|
"following_user_id" integer,
|
||||||
|
"followed_user_id" integer,
|
||||||
|
"created_at" timestamp
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "users" (
|
||||||
|
"id" integer PRIMARY KEY,
|
||||||
|
"username" varchar,
|
||||||
|
"role" varchar,
|
||||||
|
"created_at" timestamp
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "posts" (
|
||||||
|
"id" integer PRIMARY KEY,
|
||||||
|
"title" varchar,
|
||||||
|
"body" text,
|
||||||
|
"user_id" integer,
|
||||||
|
"status" varchar,
|
||||||
|
"created_at" timestamp
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMENT ON COLUMN "posts"."body" IS 'Content of the post';
|
||||||
|
|
||||||
|
ALTER TABLE "posts" ADD FOREIGN KEY ("user_id") REFERENCES "users" ("id");
|
||||||
|
|
||||||
|
ALTER TABLE "follows" ADD FOREIGN KEY ("following_user_id") REFERENCES "users" ("id");
|
||||||
|
|
||||||
|
ALTER TABLE "follows" ADD FOREIGN KEY ("followed_user_id") REFERENCES "users" ("id");
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 117 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 118 KiB |
@@ -0,0 +1,13 @@
|
|||||||
|
import axiosInstance from "@/axios/axiosInstance";
|
||||||
|
import {AxiosError} from "axios";
|
||||||
|
|
||||||
|
export const getArzeshEmtiyaz = async ()=>{
|
||||||
|
try {
|
||||||
|
const result = await axiosInstance.get(`emtiyazat/arzesh/`, )
|
||||||
|
return result.data;
|
||||||
|
} catch (error) {
|
||||||
|
if(error instanceof AxiosError){
|
||||||
|
console.log(error.response?.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import axiosInstance from "@/axios/axiosInstance";
|
||||||
|
//import axios error
|
||||||
|
import { AxiosError } from "axios";
|
||||||
|
|
||||||
|
|
||||||
|
export const getMojrian = async (status:string='WT')=>{
|
||||||
|
try {
|
||||||
|
const result = await axiosInstance.get(`op/list-mojrian/?status=${status}`,);
|
||||||
|
return result.data;
|
||||||
|
} catch (error) {
|
||||||
|
if(error instanceof AxiosError){
|
||||||
|
console.log(error.response?.data)
|
||||||
|
return error.response?.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getMojri = async (id:number)=>{
|
||||||
|
try {
|
||||||
|
const result = await axiosInstance.get(`op/mojri/${id}/`,);
|
||||||
|
return result.data;
|
||||||
|
} catch (error) {
|
||||||
|
if(error instanceof AxiosError){
|
||||||
|
console.log(error.response?.data)
|
||||||
|
return error.response?.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const updateMojriStatus = async (data:any)=>{
|
||||||
|
try {
|
||||||
|
const result = await axiosInstance.patch(`op/mojri/${data.id}/update-status/`,{mojri_status:data.status});
|
||||||
|
return result.data;
|
||||||
|
} catch (error) {
|
||||||
|
if(error instanceof AxiosError){
|
||||||
|
console.log(error.response?.data)
|
||||||
|
return error.response?.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import axiosInstance from "@/axios/axiosInstance";
|
||||||
|
import {AxiosError} from "axios";
|
||||||
|
|
||||||
|
|
||||||
|
export const getOrder = async (order_id:number)=>{
|
||||||
|
try {
|
||||||
|
const result = await axiosInstance.get(`op/order/${order_id}/`)
|
||||||
|
return result.data;
|
||||||
|
} catch (error) {
|
||||||
|
if(error instanceof AxiosError){
|
||||||
|
console.log(error.response?.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const updateOrder = async (data:any)=>{
|
||||||
|
try {
|
||||||
|
const result = await axiosInstance.patch(`op/order/${data.order_id}/update/`,{
|
||||||
|
code: data.code,
|
||||||
|
desc: data.desc
|
||||||
|
})
|
||||||
|
return result.data;
|
||||||
|
} catch (error) {
|
||||||
|
if(error instanceof AxiosError){
|
||||||
|
console.log(error.response?.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getOrderList = async (is_used:string='waiting')=>{
|
||||||
|
try {
|
||||||
|
const result = await axiosInstance.get(`op/order/list/?status=${is_used}`, )
|
||||||
|
return result.data;
|
||||||
|
} catch (error) {
|
||||||
|
if(error instanceof AxiosError){
|
||||||
|
console.log(error.response?.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import axiosInstance from "@/axios/axiosInstance";
|
||||||
|
//import axios error
|
||||||
|
import { AxiosError } from "axios";
|
||||||
|
|
||||||
|
export const getProjects = async (projects_status:string)=>{
|
||||||
|
try {
|
||||||
|
const result = await axiosInstance.get(`project/op-list/?status=${projects_status}`, )
|
||||||
|
return result.data;
|
||||||
|
} catch (error) {
|
||||||
|
if(error instanceof AxiosError){
|
||||||
|
console.log(error.response?.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getProject = async (id:number)=>{
|
||||||
|
try {
|
||||||
|
const result = await axiosInstance.get(`op/project/${id}/`)
|
||||||
|
const data = await result.data;
|
||||||
|
console.log(data)
|
||||||
|
return data
|
||||||
|
} catch (error) {
|
||||||
|
if(error instanceof AxiosError){
|
||||||
|
console.log(error.response?.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const addEmtiaz = async (emtiaz_data:any)=>{
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await axiosInstance.post(`op/project/${emtiaz_data.project_id}/add-emtiyaz/`,emtiaz_data.data)
|
||||||
|
return result.data
|
||||||
|
} catch (error) {
|
||||||
|
if(error instanceof AxiosError){
|
||||||
|
console.log(error.response?.data)
|
||||||
|
return error.response?.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import axiosInstance from "@/axios/axiosInstance";
|
||||||
|
//import axios error
|
||||||
|
import { AxiosError } from "axios";
|
||||||
|
|
||||||
|
export const createProjectCode = async (data:any)=>{
|
||||||
|
try {
|
||||||
|
const result = await axiosInstance.post(`projectcode/create/`, data)
|
||||||
|
return result.data;
|
||||||
|
} catch (error) {
|
||||||
|
if(error instanceof AxiosError){
|
||||||
|
console.log(error.response?.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getProjectCodes = async (id:number, is_used:string='false')=>{
|
||||||
|
try {
|
||||||
|
const result = await axiosInstance.get(`projectcode/list/${id}/?is_used=${is_used}`, )
|
||||||
|
return result.data;
|
||||||
|
} catch (error) {
|
||||||
|
if(error instanceof AxiosError){
|
||||||
|
console.log(error.response?.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getProjectCodeHeads = async ()=>{
|
||||||
|
try {
|
||||||
|
const result = await axiosInstance.get(`projectcode/list/`, )
|
||||||
|
return result.data;
|
||||||
|
} catch (error) {
|
||||||
|
if(error instanceof AxiosError){
|
||||||
|
console.log(error.response?.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import {Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";
|
||||||
|
import {IProject} from "@/types/project";
|
||||||
|
import {numberWithCommas} from "@/utils/helper";
|
||||||
|
import {useRouter} from "next/navigation";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
|
export default function CodeLayout({children,}: { children: React.ReactNode }) {
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const changePage = (e:any)=>{
|
||||||
|
const page_name = e.target.value
|
||||||
|
router.push(`/projects/${page_name}`)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className="w-full md:w-[60%] lg:w-[75%] m-auto " dir="rtl">
|
||||||
|
|
||||||
|
<div className="bg-white rounded-md p-4 flex flex-row mt-7 mb-3 justify-between items-center">
|
||||||
|
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p>لیست کدهای ثبت پروژه </p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={'bg-red-800 text-white rounded-xl px-4 py-1'}>
|
||||||
|
<Link href={'/code/new'}>ایجاد کد</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div className="mt-0">
|
||||||
|
|
||||||
|
<div className="flex flex-row gap-x-8 bg-white rounded p-4">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
'use client'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import {useQuery} from "@tanstack/react-query";
|
||||||
|
import moment from "moment-jalaali";
|
||||||
|
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCaption,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from "@/components/ui/table"
|
||||||
|
import { IProject } from "@/types/project"
|
||||||
|
import {numberWithCommas} from "@/utils/helper";
|
||||||
|
import {useGetProjectCodeHeads} from "@/queries/projectcode";
|
||||||
|
|
||||||
|
const Page = ()=>{
|
||||||
|
const {data, isLoading, isError, isSuccess} = useGetProjectCodeHeads()
|
||||||
|
|
||||||
|
if(isLoading){
|
||||||
|
return <div>Loading...</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isError){
|
||||||
|
return <div>Error</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<Table>
|
||||||
|
<TableCaption>لیست کدهای ثبت پروژه</TableCaption>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead className="w-[100px] text-center">شناسه</TableHead>
|
||||||
|
<TableHead className={"text-center"} >عنوان</TableHead>
|
||||||
|
<TableHead className={"text-center"} >تعداد</TableHead>
|
||||||
|
<TableHead className={"text-center"} >تاریخ ایجاد</TableHead>
|
||||||
|
|
||||||
|
<TableHead className="text-center">خروجی اکسل</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{isSuccess ? data?.map((code_head:any, key:number)=>(
|
||||||
|
<TableRow className={'*:text-center'} key={key}>
|
||||||
|
<TableCell>{key+1}</TableCell>
|
||||||
|
<TableCell>{code_head.title}</TableCell>
|
||||||
|
<TableCell>{code_head.count}</TableCell>
|
||||||
|
<TableCell>{moment(code_head.created_at).format('jYYYY/jM/jD HH:mm')}</TableCell>
|
||||||
|
|
||||||
|
<TableCell>
|
||||||
|
<Link href={`${process.env.NEXT_PUBLIC_API_URL}/projectcode/excel/${code_head.id}/`}>
|
||||||
|
خروجی اکسل
|
||||||
|
</Link>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)): null}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page;
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import {Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";
|
||||||
|
import {IProject} from "@/types/project";
|
||||||
|
import {numberWithCommas} from "@/utils/helper";
|
||||||
|
import {useRouter} from "next/navigation";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
|
export default function CodeLayout({children, params}: { children: React.ReactNode, params: {id: number} }) {
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const changePage = (e:any)=>{
|
||||||
|
const page_name = e.target.value
|
||||||
|
router.push(`/code/${params.id}/${page_name}`)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className="w-full md:w-[60%] lg:w-[75%] m-auto " dir="rtl">
|
||||||
|
|
||||||
|
<div className="bg-white rounded-md p-4 flex flex-row mt-7 mb-3 justify-between items-center">
|
||||||
|
|
||||||
|
|
||||||
|
<div className="flex flex-row gap-x-2">
|
||||||
|
<p>لیست کدهای ثبت پروژه </p>
|
||||||
|
<select onChange={changePage} id="changePage">
|
||||||
|
<option value={''}>همه</option>
|
||||||
|
<option value={'used'}>استفاده شده</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div className="mt-0">
|
||||||
|
|
||||||
|
<div className="flex flex-row gap-x-8 bg-white rounded p-4">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
'use client'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import {useQuery} from "@tanstack/react-query";
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCaption,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from "@/components/ui/table"
|
||||||
|
import { IProject } from "@/types/project"
|
||||||
|
import {numberWithCommas} from "@/utils/helper";
|
||||||
|
import {useGetProjectCodeHeads, useGetProjectCodes} from "@/queries/projectcode";
|
||||||
|
|
||||||
|
const Page = ({params}: {params: {id:number}})=>{
|
||||||
|
const {data:project_codes, isLoading, isError} = useGetProjectCodes(params.id, 'false')
|
||||||
|
|
||||||
|
if(isLoading){
|
||||||
|
return <div>Loading...</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isError){
|
||||||
|
return <div>Error</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<Table>
|
||||||
|
<TableCaption>لیست کدهای ثبت پروژه</TableCaption>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead className="w-[100px] text-center">شناسه</TableHead>
|
||||||
|
<TableHead className={"text-center"} >کد</TableHead>
|
||||||
|
<TableHead className={"text-center"} >وضغیت</TableHead>
|
||||||
|
<TableHead className={"text-center"} >فعال</TableHead>
|
||||||
|
<TableHead className="text-center">عنوان</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{project_codes.map((code:any, key:number)=>(
|
||||||
|
<TableRow className={'*:text-center'} key={key}>
|
||||||
|
<TableCell>{key+1}</TableCell>
|
||||||
|
<TableCell>{code.code}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{code.is_used ? (<>استفاده شده</>) : (
|
||||||
|
<>استفاده نشده</>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{code.is_active ? (<>فعال</>) : (
|
||||||
|
<>غیر فعال</>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{code.project_code_head}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page;
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
'use client'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import {useQuery} from "@tanstack/react-query";
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCaption,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from "@/components/ui/table"
|
||||||
|
import { IProject } from "@/types/project"
|
||||||
|
import {numberWithCommas} from "@/utils/helper";
|
||||||
|
import {useGetProjectCodeHeads, useGetProjectCodes} from "@/queries/projectcode";
|
||||||
|
|
||||||
|
const Page = ({params}: {params: {id:number}})=>{
|
||||||
|
const {data:project_codes, isLoading, isError} = useGetProjectCodes(params.id, 'true')
|
||||||
|
|
||||||
|
if(isLoading){
|
||||||
|
return <div>Loading...</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isError){
|
||||||
|
return <div>Error</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<Table>
|
||||||
|
<TableCaption>لیست کدهای ثبت پروژه</TableCaption>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead className="w-[100px] text-center">شناسه</TableHead>
|
||||||
|
<TableHead className={"text-center"} >کد</TableHead>
|
||||||
|
<TableHead className={"text-center"} >وضغیت</TableHead>
|
||||||
|
<TableHead className={"text-center"} >فعال</TableHead>
|
||||||
|
<TableHead className="text-center">عنوان</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{project_codes.map((code:any, key:number)=>(
|
||||||
|
<TableRow className={'*:text-center'} key={key}>
|
||||||
|
<TableCell>{key+1}</TableCell>
|
||||||
|
<TableCell>{code.code}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{code.is_used ? (<>استفاده شده</>) : (
|
||||||
|
<>استفاده نشده</>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{code.is_active ? (<>فعال</>) : (
|
||||||
|
<>غیر فعال</>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{code.project_code_head}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page;
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import {Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";
|
||||||
|
import {IProject} from "@/types/project";
|
||||||
|
import {numberWithCommas} from "@/utils/helper";
|
||||||
|
import {useRouter} from "next/navigation";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
|
export default function CodeLayout({children,}: { children: React.ReactNode }) {
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const changePage = (e:any)=>{
|
||||||
|
const page_name = e.target.value
|
||||||
|
router.push(`/projects/${page_name}`)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className="w-full md:w-[60%] lg:w-[75%] m-auto " dir="rtl">
|
||||||
|
|
||||||
|
<div className="bg-white rounded-md p-4 flex flex-row mt-7 mb-3 justify-between items-center">
|
||||||
|
|
||||||
|
|
||||||
|
<div className="flex flex-row gap-x-2">
|
||||||
|
<p>تولید کد ثبت پروژه</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div className="mt-0">
|
||||||
|
|
||||||
|
<div className="flex flex-row gap-x-8 bg-white rounded p-4">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
'use client'
|
||||||
|
// import react-hook-from
|
||||||
|
import {useForm, SubmitHandler} from "react-hook-form";
|
||||||
|
import {Input} from "@/components/ui/input";
|
||||||
|
import {Label} from "@/components/ui/label";
|
||||||
|
import {useProjectCodeMutation} from "@/queries/projectcode";
|
||||||
|
|
||||||
|
type Inputs = {
|
||||||
|
title: string
|
||||||
|
count: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const Page = ()=>{
|
||||||
|
|
||||||
|
const {register, handleSubmit, control, formState: { errors },} = useForm<Inputs>();
|
||||||
|
|
||||||
|
const {mutate: createProjectCode, data:project_code, isError, isSuccess, isPending} = useProjectCodeMutation()
|
||||||
|
|
||||||
|
const onSubmit:SubmitHandler<Inputs> = (data)=>{
|
||||||
|
createProjectCode(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={"flex flex-row gap-2 items-center justify-center m-auto w-[35%]"}>
|
||||||
|
|
||||||
|
<form className={'w-full flex flex-col gap-y-2'} onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<Label>
|
||||||
|
عنوان
|
||||||
|
<Input className={'mt-1'} type={"text"} {...register("title", {
|
||||||
|
required: {
|
||||||
|
value: true,
|
||||||
|
message: 'عنوان ضروری است'
|
||||||
|
},
|
||||||
|
minLength: {
|
||||||
|
value: 3,
|
||||||
|
message: 'عنوان مناسب وارد کنید'
|
||||||
|
},
|
||||||
|
})}/>
|
||||||
|
</Label>
|
||||||
|
|
||||||
|
<p className={'text-red-500'}>{errors.title?.message}</p>
|
||||||
|
|
||||||
|
<Label>
|
||||||
|
تعداد
|
||||||
|
<Input className={'mt-1'} type={"text"} {...register("count", {
|
||||||
|
required: {
|
||||||
|
value: true,
|
||||||
|
message: 'تعداد ضروری است'
|
||||||
|
},
|
||||||
|
pattern: {
|
||||||
|
value: /^[0-9]+$/,
|
||||||
|
message: 'فقط عدد وارد کنید'
|
||||||
|
}
|
||||||
|
})}/>
|
||||||
|
</Label>
|
||||||
|
<p className={'text-red-500'}>{errors.count?.message}</p>
|
||||||
|
|
||||||
|
{ !isPending && !isSuccess ? (
|
||||||
|
<input value={'تولید کد'} className={'bg-gray-800 text-white text-center rounded p-1'} type="submit"/>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page;
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import "../globals.css";
|
||||||
|
import localFont from 'next/font/local'
|
||||||
|
import SideRight from "@/components/main/side-right";
|
||||||
|
import NavTop from "@/components/main/nav-top";
|
||||||
|
import ReactQueryProvider from "@/providers/react_query";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "مدیریت باشگاه مجریان",
|
||||||
|
description: "مدیریت باشگاه مجریان",
|
||||||
|
};
|
||||||
|
|
||||||
|
const myFont = localFont({
|
||||||
|
src: '../fonts/woff2/IRANSansX-Regular.woff2',
|
||||||
|
display: 'swap',
|
||||||
|
})
|
||||||
|
|
||||||
|
export default function RootLayout({children, }: Readonly<{ children: React.ReactNode; }>) {
|
||||||
|
return (
|
||||||
|
<html lang="fa" dir="rtl" className={myFont.className}>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<ReactQueryProvider>
|
||||||
|
|
||||||
|
<NavTop />
|
||||||
|
|
||||||
|
<div className="flex min-h-screen h-screen">
|
||||||
|
|
||||||
|
<SideRight/>
|
||||||
|
|
||||||
|
<div className="flex-1 maisn-wrp pt-10 bg-slate-200">
|
||||||
|
<div className="bg-slate-200 w-full min-h-screen pb-14">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</ReactQueryProvider>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
'use client'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import {useQuery} from "@tanstack/react-query";
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCaption,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from "@/components/ui/table"
|
||||||
|
import { IMojrian } from "@/types/mojrian"
|
||||||
|
import {numberWithCommas} from "@/utils/helper";
|
||||||
|
import {useGetMojrian} from "@/queries/mojrian";
|
||||||
|
|
||||||
|
const Page = ()=>{
|
||||||
|
const {data:mojrian, isLoading, isError} = useGetMojrian('AP')
|
||||||
|
|
||||||
|
if(isLoading){
|
||||||
|
return <div>Loading...</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isError){
|
||||||
|
return <div>Error</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<Table>
|
||||||
|
<TableCaption>مجریان</TableCaption>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead className="w-[250px] text-center">نام ونام خانوادگی</TableHead>
|
||||||
|
<TableHead className={"text-center"} >استان</TableHead>
|
||||||
|
<TableHead className={"text-center"} >شهر</TableHead>
|
||||||
|
<TableHead className={"text-center"} >آدرس</TableHead>
|
||||||
|
<TableHead className="text-center">مشاهده</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{mojrian?.results?.map((mojri:IMojrian, key:number)=>(
|
||||||
|
<TableRow className={'*:text-center'} key={key}>
|
||||||
|
<TableCell>{mojri?.name_family}</TableCell>
|
||||||
|
<TableCell>{mojri?.user_profile?.city?.ostan?.name}</TableCell>
|
||||||
|
<TableCell>{mojri?.user_profile?.city?.name}</TableCell>
|
||||||
|
<TableCell>{mojri?.user_profile?.address}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Link href={`/mojrian/${mojri.id}/`}>
|
||||||
|
مشاهده
|
||||||
|
</Link>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page;
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import {Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";
|
||||||
|
import {IProject} from "@/types/project";
|
||||||
|
import {numberWithCommas} from "@/utils/helper";
|
||||||
|
import {useRouter} from "next/navigation";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
|
export default function ProjectLayout({children,}: { children: React.ReactNode }) {
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const changePage = (e:any)=>{
|
||||||
|
const page_name = e.target.value
|
||||||
|
router.push(`/mojrian/${page_name}`)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className="w-full md:w-[60%] lg:w-[75%] m-auto " dir="rtl">
|
||||||
|
|
||||||
|
<div className="bg-white rounded-md p-4 flex flex-row mt-7 mb-3 justify-between items-center">
|
||||||
|
|
||||||
|
|
||||||
|
<div className="flex flex-row gap-x-2">
|
||||||
|
<div>مجریان</div>
|
||||||
|
<select onChange={changePage} id="changePage">
|
||||||
|
<option value={''}>در انتظار تایید</option>
|
||||||
|
<option value={'approv'}>تایید شده</option>
|
||||||
|
<option value={'reject'}> رد شده</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div className="mt-0">
|
||||||
|
|
||||||
|
<div className="flex flex-row gap-x-8 bg-white rounded p-4">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
'use client'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import {useQuery} from "@tanstack/react-query";
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCaption,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from "@/components/ui/table"
|
||||||
|
import { IMojrian } from "@/types/mojrian"
|
||||||
|
import {numberWithCommas} from "@/utils/helper";
|
||||||
|
import {useGetMojrian} from "@/queries/mojrian";
|
||||||
|
|
||||||
|
const Page = ()=>{
|
||||||
|
const {data:mojrian, isLoading, isError} = useGetMojrian()
|
||||||
|
|
||||||
|
if(isLoading){
|
||||||
|
return <div>Loading...</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isError){
|
||||||
|
return <div>Error</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<Table>
|
||||||
|
<TableCaption>مجریان</TableCaption>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead className="w-[250px] text-center">نام ونام خانوادگی</TableHead>
|
||||||
|
<TableHead className={"text-center"} >استان</TableHead>
|
||||||
|
<TableHead className={"text-center"} >شهر</TableHead>
|
||||||
|
<TableHead className={"text-center"} >آدرس</TableHead>
|
||||||
|
<TableHead className="text-center">مشاهده</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{mojrian?.results?.map((mojri:IMojrian, key:number)=>(
|
||||||
|
<TableRow className={'*:text-center'} key={key}>
|
||||||
|
<TableCell>{mojri?.name_family}</TableCell>
|
||||||
|
<TableCell>{mojri?.user_profile?.city?.ostan?.name}</TableCell>
|
||||||
|
<TableCell>{mojri?.user_profile?.city?.name}</TableCell>
|
||||||
|
<TableCell>{mojri?.user_profile?.address}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Link href={`/mojrian/${mojri.id}/`}>
|
||||||
|
مشاهده
|
||||||
|
</Link>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page;
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
'use client'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import {useQuery} from "@tanstack/react-query";
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCaption,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from "@/components/ui/table"
|
||||||
|
import { IMojrian } from "@/types/mojrian"
|
||||||
|
import {numberWithCommas} from "@/utils/helper";
|
||||||
|
import {useGetMojrian} from "@/queries/mojrian";
|
||||||
|
|
||||||
|
const Page = ()=>{
|
||||||
|
const {data:mojrian, isLoading, isError} = useGetMojrian('RJ')
|
||||||
|
|
||||||
|
if(isLoading){
|
||||||
|
return <div>Loading...</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isError){
|
||||||
|
return <div>Error</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<Table>
|
||||||
|
<TableCaption>مجریان</TableCaption>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead className="w-[250px] text-center">نام ونام خانوادگی</TableHead>
|
||||||
|
<TableHead className={"text-center"} >استان</TableHead>
|
||||||
|
<TableHead className={"text-center"} >شهر</TableHead>
|
||||||
|
<TableHead className={"text-center"} >آدرس</TableHead>
|
||||||
|
<TableHead className="text-center">مشاهده</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{mojrian?.results?.map((mojri:IMojrian, key:number)=>(
|
||||||
|
<TableRow className={'*:text-center'} key={key}>
|
||||||
|
<TableCell>{mojri?.name_family}</TableCell>
|
||||||
|
<TableCell>{mojri?.user_profile?.city?.ostan?.name}</TableCell>
|
||||||
|
<TableCell>{mojri?.user_profile?.city?.name}</TableCell>
|
||||||
|
<TableCell>{mojri?.user_profile?.address}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Link href={`/mojrian/${mojri.id}/`}>
|
||||||
|
مشاهده
|
||||||
|
</Link>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page;
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import {Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";
|
||||||
|
import {IProject} from "@/types/project";
|
||||||
|
import {numberWithCommas} from "@/utils/helper";
|
||||||
|
import {useRouter} from "next/navigation";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
|
export default function ProjectLayout({children,}: { children: React.ReactNode }) {
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const changePage = (e:any)=>{
|
||||||
|
const page_name = e.target.value
|
||||||
|
router.push(`/mojrian/${page_name}`)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className="w-full md:w-[60%] lg:w-[75%] m-auto " dir="rtl">
|
||||||
|
|
||||||
|
<div className="bg-white rounded-md p-4 flex flex-row mt-7 mb-3 justify-between items-center">
|
||||||
|
|
||||||
|
|
||||||
|
<div className="flex flex-row gap-x-2">
|
||||||
|
<div>مشاهده اطلاعات مجری</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div className="mt-0">
|
||||||
|
|
||||||
|
<div className="flex flex-row gap-x-8">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
|
||||||
|
import {useGetMojri, useMojriStatusMutation} from "@/queries/mojrian";
|
||||||
|
import { IMojrian } from '@/types/mojrian'
|
||||||
|
import Image from "next/image";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
|
const Page = ({params} : {params: {id:number} })=>{
|
||||||
|
|
||||||
|
const {data:mojri, isLoading, isError, isSuccess} : {
|
||||||
|
data: IMojrian | any,
|
||||||
|
isLoading: boolean,
|
||||||
|
isError: boolean,
|
||||||
|
isSuccess: boolean
|
||||||
|
} = useGetMojri(params.id)
|
||||||
|
|
||||||
|
const {mutate:updateMojriStatus} = useMojriStatusMutation()
|
||||||
|
|
||||||
|
const changeMojriStatus = ( {target} : React.ChangeEvent<HTMLSelectElement>) => {
|
||||||
|
const value:string = target.value;
|
||||||
|
updateMojriStatus({
|
||||||
|
id: params.id,
|
||||||
|
status: value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isLoading){
|
||||||
|
return <div>Loading...</div>
|
||||||
|
}
|
||||||
|
if(isError){
|
||||||
|
return <div>Error</div>
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className={'flex flex-row w-full gap-4'}>
|
||||||
|
|
||||||
|
<div className={'w-[40%]'}>
|
||||||
|
<div className={'flex flex-col gap-y-2 bg-white rounded overflow-hidden '}>
|
||||||
|
|
||||||
|
<div id={"title"} className={"w-full bg-gray-800 text-white"}>
|
||||||
|
<div className={'flex flex-row justify-between p-2'}>
|
||||||
|
<div>مشخصات</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id={"profile_image"} className={"flex flex-row text-center items-center justify-center"}>
|
||||||
|
{mojri?.user_profile.ax_mojri ? (
|
||||||
|
<Link target="_blank" href={`${process.env.NEXT_PUBLIC_API_URL}/media/${mojri?.user_profile.ax_mojri}`}>
|
||||||
|
<Image className={'rounded-3xl'} alt={''} width={'200'} height={'200'} src={`${process.env.NEXT_PUBLIC_API_URL}/media/${mojri?.user_profile.ax_mojri}`} />
|
||||||
|
</Link>
|
||||||
|
): null}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id={"identify"} className={'flex flex-col gap-y-2 p-2'}>
|
||||||
|
<div className={''}>
|
||||||
|
{mojri?.name_family}
|
||||||
|
</div>
|
||||||
|
<div className={''}>
|
||||||
|
{mojri?.mobile}
|
||||||
|
</div>
|
||||||
|
<div className={''}>
|
||||||
|
{mojri?.user_profile?.address}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id={"status-buttons"}>
|
||||||
|
<div className={'flex flex-col justify-center text-center p-5'}>
|
||||||
|
|
||||||
|
<div className={`flex flex-col border-[1px] p-2 rounded-xl ${ mojri.mojri_status=='WT' || mojri.mojri_status=='RJ' ? 'bg-red-500': 'bg-green-800' }`}>
|
||||||
|
<p className={'text-white mb-2'}>تعیین وضعیت مجری</p>
|
||||||
|
|
||||||
|
<select onChange={changeMojriStatus} value={mojri?.mojri_status}
|
||||||
|
className={"w-[50%] m-auto border-[1px] rounded"}>
|
||||||
|
<option value={'AP'}>تایید</option>
|
||||||
|
<option value={'WT'}>در انتظار</option>
|
||||||
|
<option value={'RJ'}>عدم تایید</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={'basis-full'}>
|
||||||
|
<div className={'bg-white rounded p-4'}>
|
||||||
|
<p>مدارک</p>
|
||||||
|
<div className={'grid grid-cols-3 gap-8 mt-2'}>
|
||||||
|
|
||||||
|
{mojri?.user_profile?.ax_mojri ? (
|
||||||
|
<div className={"border border-gray-200"}>
|
||||||
|
<div className={'w-full text-center bg-gray-800 text-white p-2'}>کارت ملی</div>
|
||||||
|
<Link target="_blank" href={`${process.env.NEXT_PUBLIC_API_URL}/media/${mojri?.user_profile.ax_meli}`}>
|
||||||
|
<Image className={'w-full'} alt={''} width={'200'} height={'200'}
|
||||||
|
src={`${process.env.NEXT_PUBLIC_API_URL}/media/${mojri?.user_profile.ax_meli}`}/>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
) : null }
|
||||||
|
|
||||||
|
|
||||||
|
{mojri?.user_profile?.ax_fani ? (
|
||||||
|
<div className={"border border-gray-200"}>
|
||||||
|
<div className={'w-full text-center bg-gray-800 text-white p-2'}>گواهینامه فنی</div>
|
||||||
|
<Link target="_blank" href={`${process.env.NEXT_PUBLIC_API_URL}/media/${mojri?.user_profile?.ax_fani}`}>
|
||||||
|
<Image className={'w-full'} alt={''} width={'200'} height={'200'}
|
||||||
|
src={`${process.env.NEXT_PUBLIC_API_URL}/media/${mojri?.user_profile?.ax_fani}`}/>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
) : null }
|
||||||
|
|
||||||
|
{mojri?.user_profile?.ax_sayer ? (
|
||||||
|
|
||||||
|
<div className={"border border-gray-200"}>
|
||||||
|
<div className={'w-full text-center bg-gray-800 text-white p-2'}>سایر</div>
|
||||||
|
<Link target="_blank" href={`${process.env.NEXT_PUBLIC_API_URL}/media/${mojri?.user_profile?.ax_sayer}`}>
|
||||||
|
<Image className={'w-full'} alt={''} width={'200'} height={'200'}
|
||||||
|
src={`${process.env.NEXT_PUBLIC_API_URL}/media/${mojri?.user_profile?.ax_sayer}`}/>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
) : null }
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
'use client'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import {useQuery} from "@tanstack/react-query";
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCaption,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from "@/components/ui/table"
|
||||||
|
import {useGetProjects} from "@/queries/project";
|
||||||
|
import { IProject } from "@/types/project"
|
||||||
|
import {numberWithCommas} from "@/utils/helper";
|
||||||
|
import {useGetOrderList} from "@/queries/order";
|
||||||
|
|
||||||
|
const Page = ()=>{
|
||||||
|
const {data:orders, isLoading, isError} = useGetOrderList('approve')
|
||||||
|
|
||||||
|
if(isLoading){
|
||||||
|
return <div>Loading...</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isError){
|
||||||
|
return <div>Error</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<Table>
|
||||||
|
<TableCaption>سفارشات ثبت شده اخیر</TableCaption>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead className="w-[100px] text-center">ردیف</TableHead>
|
||||||
|
<TableHead className="text-center">عنوان</TableHead>
|
||||||
|
<TableHead className={"text-center"}>نام و نام خانوادگی</TableHead>
|
||||||
|
<TableHead className={"text-center"} >استان</TableHead>
|
||||||
|
<TableHead className={"text-center"} >شهر</TableHead>
|
||||||
|
|
||||||
|
<TableHead className="text-center">مشاهده</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{orders?.results?.map((order:any, key:number)=>(
|
||||||
|
<TableRow className={'*:text-center'} key={key}>
|
||||||
|
<TableCell>{key+1}</TableCell>
|
||||||
|
<TableCell>{order.name}</TableCell>
|
||||||
|
<TableCell>{order.name_family}</TableCell>
|
||||||
|
<TableCell>{order.ostan}</TableCell>
|
||||||
|
<TableCell>{order.city}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Link href={`/orders/${order.id}`}>
|
||||||
|
مشاهده
|
||||||
|
</Link>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page;
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import {Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";
|
||||||
|
import {IProject} from "@/types/project";
|
||||||
|
import {numberWithCommas} from "@/utils/helper";
|
||||||
|
import {useRouter} from "next/navigation";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
|
export default function ProjectLayout({children,}: { children: React.ReactNode }) {
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const changePage = (e:any)=>{
|
||||||
|
const page_name = e.target.value
|
||||||
|
router.push(`/orders/${page_name}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-full md:w-[60%] lg:w-[75%] m-auto " dir="rtl">
|
||||||
|
|
||||||
|
<div className="bg-white rounded-md p-4 flex flex-row mt-7 mb-3 justify-between items-center">
|
||||||
|
|
||||||
|
|
||||||
|
<div className="flex flex-row gap-x-2">
|
||||||
|
<select onChange={changePage} id="changePage">
|
||||||
|
<option value={''}>سفارشات در انتظار برسی</option>
|
||||||
|
<option value={'approv'}>سفارشات تایید شده</option>
|
||||||
|
<option value={'reject'}>سفارشات رد شده</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div className="mt-0">
|
||||||
|
|
||||||
|
<div className="flex flex-row gap-x-8 bg-white rounded p-4">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
'use client'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import {useQuery} from "@tanstack/react-query";
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCaption,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from "@/components/ui/table"
|
||||||
|
import {useGetProjects} from "@/queries/project";
|
||||||
|
import { IProject } from "@/types/project"
|
||||||
|
import {numberWithCommas} from "@/utils/helper";
|
||||||
|
import {useGetOrderList,} from "@/queries/order";
|
||||||
|
import {Textarea} from "@/components/ui/textarea";
|
||||||
|
import {Label} from "@/components/ui/label";
|
||||||
|
import {Input} from "@/components/ui/input";
|
||||||
|
import { useForm, SubmitHandler } from "react-hook-form"
|
||||||
|
import {updateOrder} from "@/api/order";
|
||||||
|
|
||||||
|
type Inputs = {
|
||||||
|
desc: string
|
||||||
|
code: string
|
||||||
|
order_id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const Page = ()=>{
|
||||||
|
const {data:orders, isLoading, isError} = useGetOrderList('waiting')
|
||||||
|
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
handleSubmit,
|
||||||
|
watch,
|
||||||
|
setValue,
|
||||||
|
formState: { errors },
|
||||||
|
} = useForm<Inputs>()
|
||||||
|
|
||||||
|
const onSubmit: SubmitHandler<Inputs> = async (data) => {
|
||||||
|
console.log(data)
|
||||||
|
const result = await updateOrder(data)
|
||||||
|
console.log(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isLoading){
|
||||||
|
return <div>Loading...</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isError){
|
||||||
|
return <div>Error</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<Table>
|
||||||
|
<TableCaption>سفارشات ثبت شده اخیر</TableCaption>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead className="w-[100px] text-center">ردیف</TableHead>
|
||||||
|
<TableHead className="text-center">عنوان</TableHead>
|
||||||
|
<TableHead className={"text-center"}>نام و نام خانوادگی</TableHead>
|
||||||
|
<TableHead className={"text-center"}>موبایل</TableHead>
|
||||||
|
<TableHead className={"text-center"} >استان</TableHead>
|
||||||
|
<TableHead className={"text-center"} >شهر</TableHead>
|
||||||
|
|
||||||
|
<TableHead className="text-center">مشاهده</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{orders?.results?.map((order:any, key:number)=>(
|
||||||
|
<TableRow key={key} className={'*:text-center'}>
|
||||||
|
<TableCell>{key+1}</TableCell>
|
||||||
|
<TableCell>{order.name}</TableCell>
|
||||||
|
<TableCell>{order.name_family}</TableCell>
|
||||||
|
<TableCell>{order.mobile}</TableCell>
|
||||||
|
<TableCell>{order.ostan}</TableCell>
|
||||||
|
<TableCell>{order.city}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Link href={`orders/${order.id}/`}>
|
||||||
|
مشاهده
|
||||||
|
</Link>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page;
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
'use client'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import {useQuery} from "@tanstack/react-query";
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCaption,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from "@/components/ui/table"
|
||||||
|
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
DialogTrigger,
|
||||||
|
} from "@/components/ui/dialog"
|
||||||
|
|
||||||
|
|
||||||
|
import {useGetProjects} from "@/queries/project";
|
||||||
|
import { IProject } from "@/types/project"
|
||||||
|
import {numberWithCommas} from "@/utils/helper";
|
||||||
|
import {useGetOrderList} from "@/queries/order";
|
||||||
|
|
||||||
|
const Page = ()=>{
|
||||||
|
const {data:orders, isLoading, isError} = useGetOrderList('canceled')
|
||||||
|
|
||||||
|
if(isLoading){
|
||||||
|
return <div>Loading...</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isError){
|
||||||
|
return <div>Error</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<Table>
|
||||||
|
<TableCaption>سفارشات ثبت شده اخیر</TableCaption>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead className="w-[100px] text-center">ردیف</TableHead>
|
||||||
|
<TableHead className="text-center">عنوان</TableHead>
|
||||||
|
<TableHead className={"text-center"}>نام و نام خانوادگی</TableHead>
|
||||||
|
<TableHead className={"text-center"} >استان</TableHead>
|
||||||
|
<TableHead className={"text-center"} >شهر</TableHead>
|
||||||
|
|
||||||
|
<TableHead className="text-center">مشاهده</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{orders?.results?.map((order:any, key:number)=>(
|
||||||
|
<TableRow className={'*:text-center'} key={key}>
|
||||||
|
<TableCell>{key+1}</TableCell>
|
||||||
|
<TableCell>{order.name}</TableCell>
|
||||||
|
<TableCell>{order.name_family}</TableCell>
|
||||||
|
<TableCell>{order.ostan}</TableCell>
|
||||||
|
<TableCell>{order.city}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Link href={`/orders/${order.id}`}>
|
||||||
|
مشاهده
|
||||||
|
</Link>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page;
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import Link from "next/link";
|
||||||
|
import Image from "next/image";
|
||||||
|
import {numberWithCommas} from "@/utils/helper";
|
||||||
|
import {Label} from "@/components/ui/label";
|
||||||
|
import {Input} from "@/components/ui/input";
|
||||||
|
import {Button} from "@/components/ui/button";
|
||||||
|
import {Textarea} from "@/components/ui/textarea";
|
||||||
|
import {SubmitHandler, useForm} from "react-hook-form";
|
||||||
|
import {updateOrder} from "@/api/order";
|
||||||
|
import {useGetOrder} from "@/queries/order";
|
||||||
|
import {useEffect} from "react";
|
||||||
|
import {useQueryClient} from "@tanstack/react-query";
|
||||||
|
import { FcApproval } from "react-icons/fc";
|
||||||
|
|
||||||
|
type Inputs = {
|
||||||
|
desc: string
|
||||||
|
code: string
|
||||||
|
order_id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Params = {
|
||||||
|
id:number
|
||||||
|
}
|
||||||
|
|
||||||
|
const Page = ( {params}: {params: Params} )=>{
|
||||||
|
|
||||||
|
|
||||||
|
const {data:order, isLoading, isError, isSuccess} = useGetOrder(params.id)
|
||||||
|
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
handleSubmit,
|
||||||
|
watch,
|
||||||
|
setValue,
|
||||||
|
formState: { errors },
|
||||||
|
} = useForm<Inputs>()
|
||||||
|
|
||||||
|
const onSubmit: SubmitHandler<Inputs> = async (data) => {
|
||||||
|
const result = await updateOrder({
|
||||||
|
...data,
|
||||||
|
order_id:params.id
|
||||||
|
})
|
||||||
|
queryClient.invalidateQueries({queryKey: ['order', params.id]})
|
||||||
|
if(result){
|
||||||
|
alert('با موفقیت ثبت شد')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
setValue('desc', order?.desc)
|
||||||
|
setValue('code', order?.code)
|
||||||
|
}, [isSuccess])
|
||||||
|
|
||||||
|
if(isLoading){
|
||||||
|
return <div>loading...</div>
|
||||||
|
}
|
||||||
|
if(isError){
|
||||||
|
return <div>error...</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-full md:w-[70%] lg:w-[75%] m-auto " dir="rtl">
|
||||||
|
|
||||||
|
<div className="bg-white rounded-md p-4 flex flex-row mt-7 mb-3 justify-between items-center">
|
||||||
|
|
||||||
|
<span className=" text-md">
|
||||||
|
مشاهده سفارش
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div className="flex flex-row gap-x-2">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div className="flex flex-row gap-x-2">
|
||||||
|
|
||||||
|
<div className="flex flex-col bg-white rounded-md p-4 w-full justify-between">
|
||||||
|
|
||||||
|
{order.status == 'approve' ? (<FcApproval size={40} />) : null}
|
||||||
|
|
||||||
|
<div className={'flex flex-col gap-y-1 w-[50%] text-center pb-2 m-auto border-b-[1px] mb-5'}>
|
||||||
|
<p>
|
||||||
|
{
|
||||||
|
`
|
||||||
|
درخواست:
|
||||||
|
${order?.name}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
</p>
|
||||||
|
<Link target={'_blank'} href={`/mojrian/${order?.cuser_mojri?.id}/`}>
|
||||||
|
<p className={'text-red-700 underline'}>
|
||||||
|
{
|
||||||
|
`
|
||||||
|
مجری:
|
||||||
|
${order?.cuser_mojri?.name_family}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
</p>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<p className={'text-sm'}>
|
||||||
|
{
|
||||||
|
`
|
||||||
|
آدرس:
|
||||||
|
${order?.cuser_mojri?.user_profile?.address}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<form onSubmit={handleSubmit(onSubmit)} className={'w-[50%] m-auto'}>
|
||||||
|
|
||||||
|
<Label>
|
||||||
|
توضیحات
|
||||||
|
<Textarea {...register("desc", {
|
||||||
|
required: true,
|
||||||
|
})} className={'w-full mt-2 mb-2'} defaultValue={''}/>
|
||||||
|
</Label>
|
||||||
|
|
||||||
|
|
||||||
|
<Label>
|
||||||
|
کد / یا کد رهگیری
|
||||||
|
<Input {...register("code", {
|
||||||
|
required: true,
|
||||||
|
})} className={'w-full mt-2'} defaultValue={''}/>
|
||||||
|
</Label>
|
||||||
|
|
||||||
|
<div className="flex flex-row justify-between">
|
||||||
|
|
||||||
|
{order?.status == 'approve' ? (<input type={'submit'} value={'ویرایش'} className="bg-green-900 text-white p-2 rounded-md w-full mt-2 m-auto"/> ) : null}
|
||||||
|
|
||||||
|
{order?.status == 'waiting' ? (
|
||||||
|
<input type={'submit'} value={'ثبت'} className="bg-blue-900 text-white p-2 rounded-md w-full mt-2 m-auto"/>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default Page;
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
const Page = ()=>{
|
||||||
|
return (
|
||||||
|
<p></p>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page;
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
'use client'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import {useQuery} from "@tanstack/react-query";
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCaption,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from "@/components/ui/table"
|
||||||
|
import {useGetProjects} from "@/queries/project";
|
||||||
|
import { IProject } from "@/types/project"
|
||||||
|
import {numberWithCommas} from "@/utils/helper";
|
||||||
|
|
||||||
|
const Page = ()=>{
|
||||||
|
const {data:projects, isLoading, isError} = useGetProjects('approved')
|
||||||
|
|
||||||
|
if(isLoading){
|
||||||
|
return <div>Loading...</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isError){
|
||||||
|
return <div>Error</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<Table>
|
||||||
|
<TableCaption>پروژه های ثبت شده اخیر</TableCaption>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead className="w-[100px] text-center">شناسه</TableHead>
|
||||||
|
<TableHead className={"text-center"} >استان</TableHead>
|
||||||
|
<TableHead className={"text-center"} >شهر</TableHead>
|
||||||
|
<TableHead className={"text-center"} >آدرس</TableHead>
|
||||||
|
<TableHead className={"text-center"}>نام و نام خانوادگی</TableHead>
|
||||||
|
<TableHead className="text-center">مبلغ</TableHead>
|
||||||
|
<TableHead className="text-center">مشاهده</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{projects.map((project:IProject)=>(
|
||||||
|
<TableRow className={'*:text-center'} key={project.id}>
|
||||||
|
<TableCell>{project.id}</TableCell>
|
||||||
|
<TableCell>{project.city.ostan.name}</TableCell>
|
||||||
|
<TableCell>{project.city.name}</TableCell>
|
||||||
|
<TableCell>{project.address}</TableCell>
|
||||||
|
<TableCell>{project.cuser.name_family}</TableCell>
|
||||||
|
<TableCell>{numberWithCommas(project.factor_price)}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Link href={`/projects/${project.id}`}>
|
||||||
|
مشاهده
|
||||||
|
</Link>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page;
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import {Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";
|
||||||
|
import {IProject} from "@/types/project";
|
||||||
|
import {numberWithCommas} from "@/utils/helper";
|
||||||
|
import {useRouter} from "next/navigation";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
|
export default function ProjectLayout({children,}: { children: React.ReactNode }) {
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const changePage = (e:any)=>{
|
||||||
|
const page_name = e.target.value
|
||||||
|
router.push(`/projects/${page_name}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-full md:w-[60%] lg:w-[75%] m-auto " dir="rtl">
|
||||||
|
|
||||||
|
<div className="bg-white rounded-md p-4 flex flex-row mt-7 mb-3 justify-between items-center">
|
||||||
|
|
||||||
|
|
||||||
|
<div className="flex flex-row gap-x-2">
|
||||||
|
<select onChange={changePage} id="changePage">
|
||||||
|
<option value={''}>پروژه های در انتظار تایید</option>
|
||||||
|
<option value={'approv'}>پروژه های تایید شده</option>
|
||||||
|
<option value={'reject'}>پروژه های رد شده</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div className="mt-0">
|
||||||
|
|
||||||
|
<div className="flex flex-row gap-x-8 bg-white rounded p-4">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
'use client'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import {useQuery} from "@tanstack/react-query";
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCaption,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from "@/components/ui/table"
|
||||||
|
import {useGetProjects} from "@/queries/project";
|
||||||
|
import { IProject } from "@/types/project"
|
||||||
|
import {numberWithCommas} from "@/utils/helper";
|
||||||
|
|
||||||
|
const Page = ()=>{
|
||||||
|
const {data:projects, isLoading, isError} = useGetProjects()
|
||||||
|
|
||||||
|
if(isLoading){
|
||||||
|
return <div>Loading...</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isError){
|
||||||
|
return <div>Error</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<Table>
|
||||||
|
<TableCaption>پروژه های ثبت شده اخیر</TableCaption>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead className="w-[100px] text-center">شناسه</TableHead>
|
||||||
|
<TableHead className={"text-center"} >استان</TableHead>
|
||||||
|
<TableHead className={"text-center"} >شهر</TableHead>
|
||||||
|
<TableHead className={"text-center"} >آدرس</TableHead>
|
||||||
|
<TableHead className={"text-center"}>نام و نام خانوادگی</TableHead>
|
||||||
|
<TableHead className={"text-center"}>تلفن همراه</TableHead>
|
||||||
|
<TableHead className="text-center">مبلغ</TableHead>
|
||||||
|
<TableHead className="text-center">نام فروشنده</TableHead>
|
||||||
|
<TableHead className="text-center">تلفن فروشنده</TableHead>
|
||||||
|
<TableHead className="text-center">آدرس فروشنده</TableHead>
|
||||||
|
<TableHead className="text-center">مشاهده</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{projects?.map((project:IProject)=>(
|
||||||
|
<TableRow className={'*:text-center'} key={project.id}>
|
||||||
|
<TableCell>{project.id}</TableCell>
|
||||||
|
<TableCell>{project.city.ostan.name}</TableCell>
|
||||||
|
<TableCell>{project.city.name}</TableCell>
|
||||||
|
<TableCell>{project.address}</TableCell>
|
||||||
|
<TableCell>{project.cuser.name_family}</TableCell>
|
||||||
|
<TableCell>{project.cuser.mobile}</TableCell>
|
||||||
|
<TableCell>{numberWithCommas(project.factor_price)}</TableCell>
|
||||||
|
<TableCell>{project.seller_name}</TableCell>
|
||||||
|
<TableCell>{project.seller_mobile}</TableCell>
|
||||||
|
<TableCell>{project.seller_address}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Link href={`projects/${project.id}`}>
|
||||||
|
مشاهده
|
||||||
|
</Link>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page;
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
'use client'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import {useQuery} from "@tanstack/react-query";
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCaption,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from "@/components/ui/table"
|
||||||
|
import {useGetProjects} from "@/queries/project";
|
||||||
|
import { IProject } from "@/types/project"
|
||||||
|
import {numberWithCommas} from "@/utils/helper";
|
||||||
|
|
||||||
|
const Page = ()=>{
|
||||||
|
const {data:projects, isLoading, isError} = useGetProjects('rejected')
|
||||||
|
|
||||||
|
if(isLoading){
|
||||||
|
return <div>Loading...</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isError){
|
||||||
|
return <div>Error</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<Table>
|
||||||
|
<TableCaption>پروژه های ثبت شده اخیر</TableCaption>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead className="w-[100px] text-center">شناسه</TableHead>
|
||||||
|
<TableHead className={"text-center"} >استان</TableHead>
|
||||||
|
<TableHead className={"text-center"} >شهر</TableHead>
|
||||||
|
<TableHead className={"text-center"} >آدرس</TableHead>
|
||||||
|
<TableHead className={"text-center"}>نام و نام خانوادگی</TableHead>
|
||||||
|
<TableHead className="text-center">مبلغ</TableHead>
|
||||||
|
<TableHead className="text-center">مشاهده</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{projects.map((project:IProject)=>(
|
||||||
|
<TableRow className={'*:text-center'} key={project.id}>
|
||||||
|
<TableCell>{project.id}</TableCell>
|
||||||
|
<TableCell>{project.city.ostan.name}</TableCell>
|
||||||
|
<TableCell>{project.city.name}</TableCell>
|
||||||
|
<TableCell>{project.address}</TableCell>
|
||||||
|
<TableCell>{project.cuser.name_family}</TableCell>
|
||||||
|
<TableCell>{numberWithCommas(project.factor_price)}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Link href={`/projects/${project.id}`}>
|
||||||
|
مشاهده
|
||||||
|
</Link>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page;
|
||||||
@@ -0,0 +1,300 @@
|
|||||||
|
'use client'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import {useQuery} from "@tanstack/react-query";
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCaption,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from "@/components/ui/table"
|
||||||
|
import {useEmtiazMutation, useGetProject, useGetProjects} from "@/queries/project";
|
||||||
|
import { IProject } from "@/types/project"
|
||||||
|
import {numberWithCommas} from "@/utils/helper";
|
||||||
|
import { Input } from "@/components/ui/input"
|
||||||
|
import {Label} from "@/components/ui/label";
|
||||||
|
import {useState} from "react";
|
||||||
|
import {Button} from "@/components/ui/button";
|
||||||
|
import { useForm, SubmitHandler } from "react-hook-form"
|
||||||
|
import {IAddEmtiyaz} from "@/types/emtiyaz";
|
||||||
|
import Image from "next/image";
|
||||||
|
import {useGetArzeshEmtiyaz} from "@/queries/emtiyazat";
|
||||||
|
|
||||||
|
type Params = {
|
||||||
|
id:number
|
||||||
|
}
|
||||||
|
|
||||||
|
const Page = ({params}: {params: Params})=>{
|
||||||
|
|
||||||
|
const [arzesh, setArzesh] = useState<number | null>(null)
|
||||||
|
const [arzeshError, setArzeshError] = useState<string | null>(null)
|
||||||
|
|
||||||
|
const {data:project, isError, isLoading}:{data:any, isError:any, isLoading:any} = useGetProject(params.id)
|
||||||
|
const {data:arzeshEmtiyaz, isError: isErrorEmtiyaz, isLoading: isLoadingEmtiyaz, isSuccess: isSuccessEmtiyaz} = useGetArzeshEmtiyaz()
|
||||||
|
const {mutate:addEmtiyaz,isSuccess:isSuccessEmtiaz, isError:isErrorEmtiaz,isPending:isPendingEmtiaz, data:dataEmtiaz, error:errorEmtiaz} = useEmtiazMutation()
|
||||||
|
|
||||||
|
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
handleSubmit,
|
||||||
|
watch,
|
||||||
|
formState: { errors },
|
||||||
|
} = useForm<IAddEmtiyaz>()
|
||||||
|
|
||||||
|
const onSubmit: SubmitHandler<IAddEmtiyaz> = (data) => {
|
||||||
|
|
||||||
|
const data_emtiyaz = {
|
||||||
|
project_id: params.id,
|
||||||
|
data: {
|
||||||
|
credit: data.emtiyaz
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addEmtiyaz(data_emtiyaz)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const onChangeEmtiaz = (e:any)=>{
|
||||||
|
const arzesh_emtiyaz = arzeshEmtiyaz?.arzesh_emtiyaz
|
||||||
|
|
||||||
|
const zirkol = project?.zirbana * project?.tabaghat
|
||||||
|
const max_arzesh = zirkol * arzesh_emtiyaz
|
||||||
|
const arzesh = e.target.value * arzesh_emtiyaz
|
||||||
|
if(arzesh <= max_arzesh){
|
||||||
|
setArzeshError(null)
|
||||||
|
}else {
|
||||||
|
/* const message = `حداکثر ${zirkol} امتیاز معدل ${numberWithCommas(max_arzesh)} تومان قابل قبول است `
|
||||||
|
setArzeshError(message) */
|
||||||
|
}
|
||||||
|
setArzesh(arzesh)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isLoading){
|
||||||
|
return <div>Loading...</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isError){
|
||||||
|
return <div>Error</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-full md:w-[70%] lg:w-[75%] m-auto " dir="rtl">
|
||||||
|
|
||||||
|
<div className="bg-white rounded-md p-4 flex flex-row mt-7 mb-3 justify-between items-center">
|
||||||
|
|
||||||
|
<span className=" text-md">
|
||||||
|
مشاهده پروژه
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div className="flex flex-row gap-x-2">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div className="flex flex-row gap-x-2">
|
||||||
|
|
||||||
|
<div className="w-[50%] flex flex-col gap-x-8 gap-y-2 ">
|
||||||
|
|
||||||
|
<div className={'bg-white rounded p-4'}>
|
||||||
|
<div className={'border-b-[1px] border-b-gray-200 pb-1 w-full'}>
|
||||||
|
مشخصات مجری
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={"pt-2 flex flex-col gap-y-2"}>
|
||||||
|
<div className={"flex flex-row items-center gap-x-2"}>
|
||||||
|
<span className={'text-md'}>نام مجری:</span>
|
||||||
|
<span className={'text-sm'}>
|
||||||
|
{project?.cuser?.name_family}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={"flex flex-row items-center gap-x-2"}>
|
||||||
|
<span className={'text-md'}>تلفن مجری:</span>
|
||||||
|
<span className={'text-sm'}>
|
||||||
|
{project?.cuser?.mobile}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={'bg-white rounded p-4'}>
|
||||||
|
<div className={'border-b-[1px] border-b-gray-200 pb-1 w-full'}>
|
||||||
|
مشخصات فروشنده
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={"pt-2 flex flex-col gap-y-2"}>
|
||||||
|
<div className={"flex flex-row items-center gap-x-2"}>
|
||||||
|
<span className={'text-md'}>نام فروشنده:</span>
|
||||||
|
<span className={'text-sm'}>
|
||||||
|
{project?.seller_name}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={"flex flex-row items-center gap-x-2"}>
|
||||||
|
<span className={'text-md'}>تلفن فروشنده:</span>
|
||||||
|
<span className={'text-sm'}>
|
||||||
|
{project?.seller_mobile}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={"flex flex-row items-center gap-x-2"}>
|
||||||
|
<span className={'text-md'}>آدرس فروشنده:</span>
|
||||||
|
<span className={'text-sm'}>
|
||||||
|
{project?.seller_address}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="basis-full bg-white rounded p-4">
|
||||||
|
|
||||||
|
<div className={'p-0 m-0 w-full'}>
|
||||||
|
|
||||||
|
<div className={"border-b-[1px] border-b-gray-200 pb-1 w-full"}>
|
||||||
|
<p>مشخصات پروژه</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={'flex flex-col gap-y-4'}>
|
||||||
|
|
||||||
|
<div className={"pt-2 mb-2"}>
|
||||||
|
<div>
|
||||||
|
{project?.address}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={"p-2 flex flex-row gap-x-4 justify-between bg-gray-200 rounded items-center"}>
|
||||||
|
<div>
|
||||||
|
زیر بنا:
|
||||||
|
{project?.zirbana}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
تعداد طبقه:
|
||||||
|
{project?.tabaghat}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
تعداد واحد:
|
||||||
|
{project?.vahed}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={""}>
|
||||||
|
<div>تصاویر پروژه</div>
|
||||||
|
<div className={"grid grid-cols-4 gap-2"}>
|
||||||
|
{project?.project_image?.map((item:any, key:number)=>{
|
||||||
|
return (
|
||||||
|
<Link className={"border-[2px] border-blue-900 rounded"} href={`${process.env.NEXT_PUBLIC_API_URL}${item.image}`} target="_blank" key={key}>
|
||||||
|
<Image width={'100'} height={'100'} alt={''} src={`${process.env.NEXT_PUBLIC_API_URL}${item.image}`} className={"w-full h-full"}/>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"p-2 flex flex-row gap-x-4 justify-between bg-red-800 text-center m-auto text-white rounded items-center"}>
|
||||||
|
|
||||||
|
<p className={'text-center'}>
|
||||||
|
ارزش پروژه:
|
||||||
|
{numberWithCommas(project?.factor_price)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={'p-0 m-0 w-full mt-10'}>
|
||||||
|
{project.emtiyaz == null && project.status == 'waiting' ? (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<div className={"border-b-[1px] border-b-gray-300 pb-1 w-full mb-4"}>
|
||||||
|
<p>ثبت امتیاز پروژه</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form onSubmit={handleSubmit(onSubmit)} className={'flex flex-col gap-y-4'}>
|
||||||
|
<Label>
|
||||||
|
امتیاز
|
||||||
|
<Input {...register('emtiyaz', {
|
||||||
|
required: {
|
||||||
|
value: true,
|
||||||
|
message: "این فیلد اجباری است"
|
||||||
|
},
|
||||||
|
pattern: {
|
||||||
|
value: /^[0-9]+$/,
|
||||||
|
message: "فقط عدد وارد کنید",
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
onChange={(e) => {
|
||||||
|
onChangeEmtiaz(e)
|
||||||
|
}}
|
||||||
|
className={"mt-1 focus-visible:ring-1 focus-visible:ring-blue-800 focus-visible:outline-none focus-visible:ring-offset-1 drop-shadow-sm w-full rounded-md"}
|
||||||
|
type={"text"}/>
|
||||||
|
</Label>
|
||||||
|
|
||||||
|
<p className={'text-sm text-red-900 text-center'}>{errors?.emtiyaz?.message}</p>
|
||||||
|
|
||||||
|
<p>ارزش امتیاز:
|
||||||
|
{arzesh ? numberWithCommas(arzesh) : null}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div id={"submit"} className={"text-center"}>
|
||||||
|
|
||||||
|
{arzeshError ? <p className={'text-sm text-red-900 text-center'}>{arzeshError}</p> : (
|
||||||
|
isPendingEmtiaz ? "در حال ثبت امتیاز" : (
|
||||||
|
|
||||||
|
isSuccessEmtiaz ? null : (
|
||||||
|
<Button className={""}>ثبت امتیاز</Button>
|
||||||
|
)
|
||||||
|
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</>
|
||||||
|
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
<div className={'mt-4'}>
|
||||||
|
{project.status == 'approved' ? (
|
||||||
|
<div className={"text-center w-full bg-blue-900 text-white rounded"}>
|
||||||
|
<p>
|
||||||
|
پروژه تایید شده
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{project.status == 'rejected' ? (
|
||||||
|
<div className={"text-center w-full bg-red-900 text-white rounded"}>
|
||||||
|
<p>
|
||||||
|
پروژه رد شده
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page;
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import "../globals.css";
|
||||||
|
import localFont from 'next/font/local'
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "ورورد به باشگاه مجریان",
|
||||||
|
description: "مدیریت باشگاه مجریان",
|
||||||
|
};
|
||||||
|
|
||||||
|
const myFont = localFont({
|
||||||
|
src: '../fonts/woff2/IRANSansX-Regular.woff2',
|
||||||
|
display: 'swap',
|
||||||
|
})
|
||||||
|
|
||||||
|
export default function RootLayout({children, }: Readonly<{ children: React.ReactNode; }>) {
|
||||||
|
return (
|
||||||
|
<html lang="fa" dir="rtl" className={myFont.className}>
|
||||||
|
<body>
|
||||||
|
{children}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { Label } from "@/components/ui/label";
|
||||||
|
import Link from 'next/link'
|
||||||
|
import { useForm, SubmitHandler } from "react-hook-form"
|
||||||
|
import axios, {AxiosInstance, AxiosResponse} from "axios";
|
||||||
|
import {useState} from "react";
|
||||||
|
import { TokenType } from '@/types/login'
|
||||||
|
import {useRouter} from "next/navigation";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
|
function setCookie(name:any,value:any,days:any) {
|
||||||
|
var expires = "";
|
||||||
|
if (days) {
|
||||||
|
var date = new Date();
|
||||||
|
date.setTime(date.getTime() + (days*24*60*60*1000));
|
||||||
|
expires = "; expires=" + date.toUTCString();
|
||||||
|
}
|
||||||
|
document.cookie = name + "=" + (value || "") + expires + "; path=/";
|
||||||
|
}
|
||||||
|
|
||||||
|
type Inputs = {
|
||||||
|
username: string
|
||||||
|
password: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type User = {
|
||||||
|
username: string
|
||||||
|
password: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const Page = ()=>{
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const [loginPending, setLoginPending] = useState<boolean>(false)
|
||||||
|
|
||||||
|
const [errorMessage, setErrorMessage] = useState<string | null>(null)
|
||||||
|
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
handleSubmit,
|
||||||
|
watch,
|
||||||
|
formState: { errors },
|
||||||
|
} = useForm<Inputs>()
|
||||||
|
const onSubmit: SubmitHandler<Inputs> = async (data) => {
|
||||||
|
|
||||||
|
try {
|
||||||
|
setLoginPending(true)
|
||||||
|
setErrorMessage(null)
|
||||||
|
const result: AxiosResponse = await axios.post(`${process.env.NEXT_PUBLIC_API_URL}/auth/login-admin/`,data)
|
||||||
|
if (result.status === 200) {
|
||||||
|
const token: TokenType = result.data
|
||||||
|
setCookie('isAuthAd', 'true', 365)
|
||||||
|
localStorage.setItem('admin_at', token.access)
|
||||||
|
localStorage.setItem('admin_rt', token.refresh)
|
||||||
|
router.push('/projects/')
|
||||||
|
} else {
|
||||||
|
setErrorMessage("نام کاربری یا کلمه عبور صحیح نیست")
|
||||||
|
setLoginPending(false)
|
||||||
|
}
|
||||||
|
} catch (e: any) {
|
||||||
|
setLoginPending(false)
|
||||||
|
setErrorMessage("نام کاربری یا کلمه عبور صحیح نیست")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bg-slate-200 h-screen pt-4">
|
||||||
|
<div className="drop-shadow-md flex flex-col w-[90%] md:w-[400px] m-auto p-4 bg-white rounded-lg">
|
||||||
|
|
||||||
|
<div className="flex flex-col mb-8 text-center items-center justify-center">
|
||||||
|
|
||||||
|
<Image src={'/logo.png'} width={200} height={100} alt={'a'}/>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form onSubmit={handleSubmit(onSubmit)} className="flex flex-col gap-y-2">
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<Label>
|
||||||
|
نام کاربری
|
||||||
|
<Input type={'text'} {...register("username", {
|
||||||
|
required: "نام کاربری الزامی هست",
|
||||||
|
})}/>
|
||||||
|
</Label>
|
||||||
|
<p className={'text-sm mt-1'}>{errors?.username?.message}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<Label>
|
||||||
|
کلمه عبور
|
||||||
|
<Input type={'text'} {...register("password", {
|
||||||
|
required: "کلمه عبور الزامی است",
|
||||||
|
})}/>
|
||||||
|
</Label>
|
||||||
|
<p className={'text-sm mt-1'}>{errors?.password?.message}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div className="text-center">
|
||||||
|
{loginPending ? <p>در حال ورود...</p> : <Button className="bg-blue-600">ورود به سامانه</Button>}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>{errorMessage}</p>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page;
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+71
-28
@@ -1,33 +1,76 @@
|
|||||||
@tailwind base;
|
@tailwind base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
:root {
|
@layer base {
|
||||||
--foreground-rgb: 0, 0, 0;
|
:root {
|
||||||
--background-start-rgb: 214, 219, 220;
|
--background: 0 0% 100%;
|
||||||
--background-end-rgb: 255, 255, 255;
|
--foreground: 222.2 84% 4.9%;
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
--card: 0 0% 100%;
|
||||||
:root {
|
--card-foreground: 222.2 84% 4.9%;
|
||||||
--foreground-rgb: 255, 255, 255;
|
|
||||||
--background-start-rgb: 0, 0, 0;
|
--popover: 0 0% 100%;
|
||||||
--background-end-rgb: 0, 0, 0;
|
--popover-foreground: 222.2 84% 4.9%;
|
||||||
|
|
||||||
|
--primary: 222.2 47.4% 11.2%;
|
||||||
|
--primary-foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--secondary: 210 40% 96.1%;
|
||||||
|
--secondary-foreground: 222.2 47.4% 11.2%;
|
||||||
|
|
||||||
|
--muted: 210 40% 96.1%;
|
||||||
|
--muted-foreground: 215.4 16.3% 46.9%;
|
||||||
|
|
||||||
|
--accent: 210 40% 96.1%;
|
||||||
|
--accent-foreground: 222.2 47.4% 11.2%;
|
||||||
|
|
||||||
|
--destructive: 0 84.2% 60.2%;
|
||||||
|
--destructive-foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--border: 214.3 31.8% 91.4%;
|
||||||
|
--input: 214.3 31.8% 91.4%;
|
||||||
|
--ring: 222.2 84% 4.9%;
|
||||||
|
|
||||||
|
--radius: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark {
|
||||||
|
--background: 222.2 84% 4.9%;
|
||||||
|
--foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--card: 222.2 84% 4.9%;
|
||||||
|
--card-foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--popover: 222.2 84% 4.9%;
|
||||||
|
--popover-foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--primary: 210 40% 98%;
|
||||||
|
--primary-foreground: 222.2 47.4% 11.2%;
|
||||||
|
|
||||||
|
--secondary: 217.2 32.6% 17.5%;
|
||||||
|
--secondary-foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--muted: 217.2 32.6% 17.5%;
|
||||||
|
--muted-foreground: 215 20.2% 65.1%;
|
||||||
|
|
||||||
|
--accent: 217.2 32.6% 17.5%;
|
||||||
|
--accent-foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--destructive: 0 62.8% 30.6%;
|
||||||
|
--destructive-foreground: 210 40% 98%;
|
||||||
|
|
||||||
|
--border: 217.2 32.6% 17.5%;
|
||||||
|
--input: 217.2 32.6% 17.5%;
|
||||||
|
--ring: 212.7 26.8% 83.9%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
@layer base {
|
||||||
color: rgb(var(--foreground-rgb));
|
* {
|
||||||
background: linear-gradient(
|
@apply border-border;
|
||||||
to bottom,
|
}
|
||||||
transparent,
|
body {
|
||||||
rgb(var(--background-end-rgb))
|
@apply bg-background text-foreground;
|
||||||
)
|
}
|
||||||
rgb(var(--background-start-rgb));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@layer utilities {
|
|
||||||
.text-balance {
|
|
||||||
text-wrap: balance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
import type { Metadata } from "next";
|
|
||||||
import { Inter } from "next/font/google";
|
|
||||||
import "./globals.css";
|
|
||||||
|
|
||||||
const inter = Inter({ subsets: ["latin"] });
|
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
|
||||||
title: "Create Next App",
|
|
||||||
description: "Generated by create next app",
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function RootLayout({
|
|
||||||
children,
|
|
||||||
}: Readonly<{
|
|
||||||
children: React.ReactNode;
|
|
||||||
}>) {
|
|
||||||
return (
|
|
||||||
<html lang="en">
|
|
||||||
<body className={inter.className}>{children}</body>
|
|
||||||
</html>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
import Image from "next/image";
|
|
||||||
|
|
||||||
export default function Home() {
|
|
||||||
return (
|
|
||||||
<main className="flex min-h-screen flex-col items-center justify-between p-24">
|
|
||||||
<div className="z-10 w-full max-w-5xl items-center justify-between font-mono text-sm lg:flex">
|
|
||||||
<p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">
|
|
||||||
Get started by editing
|
|
||||||
<code className="font-mono font-bold">src/app/page.tsx</code>
|
|
||||||
</p>
|
|
||||||
<div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:size-auto lg:bg-none">
|
|
||||||
<a
|
|
||||||
className="pointer-events-none flex place-items-center gap-2 p-8 lg:pointer-events-auto lg:p-0"
|
|
||||||
href="https://vercel.com?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
By{" "}
|
|
||||||
<Image
|
|
||||||
src="/vercel.svg"
|
|
||||||
alt="Vercel Logo"
|
|
||||||
className="dark:invert"
|
|
||||||
width={100}
|
|
||||||
height={24}
|
|
||||||
priority
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="relative z-[-1] flex place-items-center before:absolute before:h-[300px] before:w-full before:-translate-x-1/2 before:rounded-full before:bg-gradient-radial before:from-white before:to-transparent before:blur-2xl before:content-[''] after:absolute after:-z-20 after:h-[180px] after:w-full after:translate-x-1/3 after:bg-gradient-conic after:from-sky-200 after:via-blue-200 after:blur-2xl after:content-[''] before:dark:bg-gradient-to-br before:dark:from-transparent before:dark:to-blue-700 before:dark:opacity-10 after:dark:from-sky-900 after:dark:via-[#0141ff] after:dark:opacity-40 sm:before:w-[480px] sm:after:w-[240px] before:lg:h-[360px]">
|
|
||||||
<Image
|
|
||||||
className="relative dark:drop-shadow-[0_0_0.3rem_#ffffff70] dark:invert"
|
|
||||||
src="/next.svg"
|
|
||||||
alt="Next.js Logo"
|
|
||||||
width={180}
|
|
||||||
height={37}
|
|
||||||
priority
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mb-32 grid text-center lg:mb-0 lg:w-full lg:max-w-5xl lg:grid-cols-4 lg:text-left">
|
|
||||||
<a
|
|
||||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
|
||||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<h2 className="mb-3 text-2xl font-semibold">
|
|
||||||
Docs{" "}
|
|
||||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
|
||||||
->
|
|
||||||
</span>
|
|
||||||
</h2>
|
|
||||||
<p className="m-0 max-w-[30ch] text-sm opacity-50">
|
|
||||||
Find in-depth information about Next.js features and API.
|
|
||||||
</p>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a
|
|
||||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
|
||||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<h2 className="mb-3 text-2xl font-semibold">
|
|
||||||
Learn{" "}
|
|
||||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
|
||||||
->
|
|
||||||
</span>
|
|
||||||
</h2>
|
|
||||||
<p className="m-0 max-w-[30ch] text-sm opacity-50">
|
|
||||||
Learn about Next.js in an interactive course with quizzes!
|
|
||||||
</p>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a
|
|
||||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
|
||||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<h2 className="mb-3 text-2xl font-semibold">
|
|
||||||
Templates{" "}
|
|
||||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
|
||||||
->
|
|
||||||
</span>
|
|
||||||
</h2>
|
|
||||||
<p className="m-0 max-w-[30ch] text-sm opacity-50">
|
|
||||||
Explore starter templates for Next.js.
|
|
||||||
</p>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a
|
|
||||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
|
||||||
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<h2 className="mb-3 text-2xl font-semibold">
|
|
||||||
Deploy{" "}
|
|
||||||
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
|
||||||
->
|
|
||||||
</span>
|
|
||||||
</h2>
|
|
||||||
<p className="m-0 max-w-[30ch] text-balance text-sm opacity-50">
|
|
||||||
Instantly deploy your Next.js site to a shareable URL with Vercel.
|
|
||||||
</p>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
|
||||||
|
//let accessToken = localStorage.getItem('access') ? localStorage.getItem('access') : null
|
||||||
|
function setCookieFn(name:string, value:string, daysToExpire:number) {
|
||||||
|
const expires = new Date();
|
||||||
|
expires.setTime(expires.getTime() + (daysToExpire * 24 * 60 * 60 * 1000));
|
||||||
|
document.cookie = `${name}=${value};expires=${expires.toUTCString()};path=/`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const axiosInstance = axios.create({
|
||||||
|
baseURL: `${process.env.NEXT_PUBLIC_API_URL}/`,
|
||||||
|
timeout: 10000,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
//'Authorization': `Bearer ${accessToken}`,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
axiosInstance.interceptors.request.use(async req => {
|
||||||
|
const accessT = localStorage.getItem('admin_at')
|
||||||
|
req.headers.Authorization = `Bearer ${accessT}`
|
||||||
|
return req
|
||||||
|
})
|
||||||
|
|
||||||
|
axiosInstance.interceptors.response.use((response)=> {
|
||||||
|
return response
|
||||||
|
}, async (error) =>{
|
||||||
|
|
||||||
|
const originalRequest = error.config;
|
||||||
|
|
||||||
|
if (error.response.status === 401 && !originalRequest._retry) {
|
||||||
|
|
||||||
|
originalRequest._retry = true; // Prevent infinite loops
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (localStorage.getItem('admin_rt') != 'undefined'){
|
||||||
|
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/auth/refresh-token/`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json; charset=UTF-8',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
'refresh': localStorage.getItem('admin_rt')
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
if(res.status==200){
|
||||||
|
setCookieFn('isAuth', 'true', 365)
|
||||||
|
const tokenData = await res.json()
|
||||||
|
localStorage.setItem('admin_at', tokenData.access)
|
||||||
|
localStorage.setItem('admin_rt',tokenData.refresh)
|
||||||
|
originalRequest.headers.Authorization = `Bearer ${tokenData.access}`
|
||||||
|
return axiosInstance(originalRequest)
|
||||||
|
}else{
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
localStorage.removeItem('admin_at');
|
||||||
|
localStorage.removeItem('admin_rt');
|
||||||
|
document.cookie = "isAuth=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
|
||||||
|
setTimeout(()=>{
|
||||||
|
window.location.replace('/login')
|
||||||
|
}, 200)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch(refreshError) {
|
||||||
|
|
||||||
|
localStorage.removeItem('admin_at');
|
||||||
|
localStorage.removeItem('admin_rt');
|
||||||
|
document.cookie = "isAuth=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
|
||||||
|
setTimeout(()=>{
|
||||||
|
window.location.replace('/login')
|
||||||
|
}, 200)
|
||||||
|
|
||||||
|
throw refreshError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a Promise rejection if the status code is not 401
|
||||||
|
return Promise.reject(error);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
export default axiosInstance
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useRouter } from 'next/navigation'
|
||||||
|
import axiosInstance from '@/axios/axiosInstance'
|
||||||
|
import { useQuery } from '@tanstack/react-query'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
|
const NavTop = ()=>{
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const [nameFamily, setNameFamily] = useState<string | null>(null)
|
||||||
|
|
||||||
|
useEffect( ()=>{
|
||||||
|
setNameFamily('مدیر')
|
||||||
|
},[])
|
||||||
|
|
||||||
|
|
||||||
|
const onLogout = ()=>{
|
||||||
|
localStorage.removeItem('admin_rt');
|
||||||
|
localStorage.removeItem('admin_at');
|
||||||
|
document.cookie = "isAuthAd=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
|
||||||
|
setTimeout(()=>{
|
||||||
|
router.push('/login')
|
||||||
|
}, 200)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className="flex flex-row pl-52 justify-between items-center menu fixed bg-slate-600 w-full z-[1000] h-10 mr-52">
|
||||||
|
<div></div>
|
||||||
|
<div className="flex flex-row gap-x-2 pl-2 items-center">
|
||||||
|
<div className="text-white">
|
||||||
|
{nameFamily ? (
|
||||||
|
<span>{nameFamily}</span>
|
||||||
|
): null}
|
||||||
|
</div>
|
||||||
|
<div onClick={onLogout} className="bg-slate-800 text-white p-1 rounded-md cursor-pointer">خروج</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NavTop
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import Link from "next/link";
|
||||||
|
import { AiFillAppstore, AiFillHome } from "react-icons/ai";
|
||||||
|
import { HiShoppingCart } from "react-icons/hi";
|
||||||
|
import { BsFillChatRightTextFill,BsFillQuestionCircleFill } from "react-icons/bs";
|
||||||
|
import { BiSolidReport, } from "react-icons/bi";
|
||||||
|
import { FaMoneyCheckDollar, FaHandHoldingDollar, FaUsers } from "react-icons/fa6";
|
||||||
|
import { MdVerified, MdOutlineRepeatOn } from "react-icons/md";
|
||||||
|
import { TbTargetArrow } from "react-icons/tb";
|
||||||
|
import { IoNotifications } from "react-icons/io5";
|
||||||
|
import { IoIosBarcode } from "react-icons/io";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const SideRight = ()=>{
|
||||||
|
|
||||||
|
const menuLinks = [
|
||||||
|
{name:'خانه', link: '/', size:25, icon: <AiFillHome size={25} color={'white'} />},
|
||||||
|
{name:'پروژه ها', link: '/projects', size:25, icon: <HiShoppingCart size={25} color={'white'} />},
|
||||||
|
{name:'درخواست ها', link: '/orders', size:25, icon: <MdVerified size={25} color={'white'} />},
|
||||||
|
{name:'مجریان', link: '/mojrian', size:25, icon: <FaUsers size={25} color={'white'} />},
|
||||||
|
{name:'کد ثبت پروژه', link: '/code', size:25, icon: <IoIosBarcode size={25} color={'white'} />},
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<aside className="w-52">
|
||||||
|
<div className="fixed w-52 h-screen bg-slate-700"></div>
|
||||||
|
<div className="flex flex-col relative pr-2 pl-2">
|
||||||
|
|
||||||
|
<div className="logo mb-4 text-white text-center pt-[1rem] border-b-[1px] pb-4">
|
||||||
|
لوله گستر گلپایگان
|
||||||
|
<p className="font-light text-sm mt-2 ">پنل مدیریت باشگاه</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="">
|
||||||
|
<ul>
|
||||||
|
{menuLinks.map((item, key)=>{
|
||||||
|
return <Link key={key} href={item.link}>
|
||||||
|
<li className="bg-slate-600 p-2 flex flex-row gap-x-2 mb-4 rounded-md">
|
||||||
|
|
||||||
|
{item.icon}
|
||||||
|
<span className="text-white">{item.name}</span>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
</Link>
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SideRight
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
import { cva, type VariantProps } from "class-variance-authority"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
const alertVariants = cva(
|
||||||
|
"relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground",
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default: "bg-background text-foreground",
|
||||||
|
destructive:
|
||||||
|
"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: "default",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const Alert = React.forwardRef<
|
||||||
|
HTMLDivElement,
|
||||||
|
React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>
|
||||||
|
>(({ className, variant, ...props }, ref) => (
|
||||||
|
<div
|
||||||
|
ref={ref}
|
||||||
|
role="alert"
|
||||||
|
className={cn(alertVariants({ variant }), className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
Alert.displayName = "Alert"
|
||||||
|
|
||||||
|
const AlertTitle = React.forwardRef<
|
||||||
|
HTMLParagraphElement,
|
||||||
|
React.HTMLAttributes<HTMLHeadingElement>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<h5
|
||||||
|
ref={ref}
|
||||||
|
className={cn("mb-1 font-medium leading-none tracking-tight", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
AlertTitle.displayName = "AlertTitle"
|
||||||
|
|
||||||
|
const AlertDescription = React.forwardRef<
|
||||||
|
HTMLParagraphElement,
|
||||||
|
React.HTMLAttributes<HTMLParagraphElement>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<div
|
||||||
|
ref={ref}
|
||||||
|
className={cn("text-sm [&_p]:leading-relaxed", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
AlertDescription.displayName = "AlertDescription"
|
||||||
|
|
||||||
|
export { Alert, AlertTitle, AlertDescription }
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
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 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
||||||
|
destructive:
|
||||||
|
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
||||||
|
outline:
|
||||||
|
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
||||||
|
secondary:
|
||||||
|
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||||
|
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||||
|
link: "text-primary underline-offset-4 hover:underline",
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
default: "h-10 px-4 py-2",
|
||||||
|
sm: "h-9 rounded-md px-3",
|
||||||
|
lg: "h-11 rounded-md px-8",
|
||||||
|
icon: "h-10 w-10",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
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,30 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
|
||||||
|
import { Check } from "lucide-react"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
const Checkbox = React.forwardRef<
|
||||||
|
React.ElementRef<typeof CheckboxPrimitive.Root>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<CheckboxPrimitive.Root
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<CheckboxPrimitive.Indicator
|
||||||
|
className={cn("flex items-center justify-center text-current")}
|
||||||
|
>
|
||||||
|
<Check className="h-4 w-4" />
|
||||||
|
</CheckboxPrimitive.Indicator>
|
||||||
|
</CheckboxPrimitive.Root>
|
||||||
|
))
|
||||||
|
Checkbox.displayName = CheckboxPrimitive.Root.displayName
|
||||||
|
|
||||||
|
export { Checkbox }
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import * as DialogPrimitive from "@radix-ui/react-dialog"
|
||||||
|
import { X } from "lucide-react"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
const Dialog = DialogPrimitive.Root
|
||||||
|
|
||||||
|
const DialogTrigger = DialogPrimitive.Trigger
|
||||||
|
|
||||||
|
const DialogPortal = DialogPrimitive.Portal
|
||||||
|
|
||||||
|
const DialogClose = DialogPrimitive.Close
|
||||||
|
|
||||||
|
const DialogOverlay = React.forwardRef<
|
||||||
|
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<DialogPrimitive.Overlay
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
|
||||||
|
|
||||||
|
const DialogContent = React.forwardRef<
|
||||||
|
React.ElementRef<typeof DialogPrimitive.Content>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
|
||||||
|
>(({ className, children, ...props }, ref) => (
|
||||||
|
<DialogPortal>
|
||||||
|
<DialogOverlay />
|
||||||
|
<DialogPrimitive.Content
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 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-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
||||||
|
<X className="h-4 w-4" />
|
||||||
|
<span className="sr-only">Close</span>
|
||||||
|
</DialogPrimitive.Close>
|
||||||
|
</DialogPrimitive.Content>
|
||||||
|
</DialogPortal>
|
||||||
|
))
|
||||||
|
DialogContent.displayName = DialogPrimitive.Content.displayName
|
||||||
|
|
||||||
|
const DialogHeader = ({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"flex flex-col space-y-1.5 text-center sm:text-left",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
DialogHeader.displayName = "DialogHeader"
|
||||||
|
|
||||||
|
const DialogFooter = ({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
DialogFooter.displayName = "DialogFooter"
|
||||||
|
|
||||||
|
const DialogTitle = React.forwardRef<
|
||||||
|
React.ElementRef<typeof DialogPrimitive.Title>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<DialogPrimitive.Title
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"text-lg font-semibold leading-none tracking-tight",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
DialogTitle.displayName = DialogPrimitive.Title.displayName
|
||||||
|
|
||||||
|
const DialogDescription = React.forwardRef<
|
||||||
|
React.ElementRef<typeof DialogPrimitive.Description>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<DialogPrimitive.Description
|
||||||
|
ref={ref}
|
||||||
|
className={cn("text-sm text-muted-foreground", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
DialogDescription.displayName = DialogPrimitive.Description.displayName
|
||||||
|
|
||||||
|
export {
|
||||||
|
Dialog,
|
||||||
|
DialogPortal,
|
||||||
|
DialogOverlay,
|
||||||
|
DialogClose,
|
||||||
|
DialogTrigger,
|
||||||
|
DialogContent,
|
||||||
|
DialogHeader,
|
||||||
|
DialogFooter,
|
||||||
|
DialogTitle,
|
||||||
|
DialogDescription,
|
||||||
|
}
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
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-sm 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-sm font-medium text-destructive", className)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{body}
|
||||||
|
</p>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
FormMessage.displayName = "FormMessage"
|
||||||
|
|
||||||
|
export {
|
||||||
|
useFormField,
|
||||||
|
Form,
|
||||||
|
FormItem,
|
||||||
|
FormLabel,
|
||||||
|
FormControl,
|
||||||
|
FormDescription,
|
||||||
|
FormMessage,
|
||||||
|
FormField,
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
export interface InputProps
|
||||||
|
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||||
|
|
||||||
|
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||||
|
({ className, type, ...props }, ref) => {
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
type={type}
|
||||||
|
className={cn(
|
||||||
|
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
|
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,160 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import * as SelectPrimitive from "@radix-ui/react-select"
|
||||||
|
import { Check, ChevronDown, ChevronUp } from "lucide-react"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
const Select = SelectPrimitive.Root
|
||||||
|
|
||||||
|
const SelectGroup = SelectPrimitive.Group
|
||||||
|
|
||||||
|
const SelectValue = SelectPrimitive.Value
|
||||||
|
|
||||||
|
const SelectTrigger = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
|
||||||
|
>(({ className, children, ...props }, ref) => (
|
||||||
|
<SelectPrimitive.Trigger
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
<SelectPrimitive.Icon asChild>
|
||||||
|
<ChevronDown className="h-4 w-4 opacity-50" />
|
||||||
|
</SelectPrimitive.Icon>
|
||||||
|
</SelectPrimitive.Trigger>
|
||||||
|
))
|
||||||
|
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
|
||||||
|
|
||||||
|
const SelectScrollUpButton = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<SelectPrimitive.ScrollUpButton
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"flex cursor-default items-center justify-center py-1",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<ChevronUp className="h-4 w-4" />
|
||||||
|
</SelectPrimitive.ScrollUpButton>
|
||||||
|
))
|
||||||
|
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
|
||||||
|
|
||||||
|
const SelectScrollDownButton = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<SelectPrimitive.ScrollDownButton
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"flex cursor-default items-center justify-center py-1",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<ChevronDown className="h-4 w-4" />
|
||||||
|
</SelectPrimitive.ScrollDownButton>
|
||||||
|
))
|
||||||
|
SelectScrollDownButton.displayName =
|
||||||
|
SelectPrimitive.ScrollDownButton.displayName
|
||||||
|
|
||||||
|
const SelectContent = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.Content>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
|
||||||
|
>(({ className, children, position = "popper", ...props }, ref) => (
|
||||||
|
<SelectPrimitive.Portal>
|
||||||
|
<SelectPrimitive.Content
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md 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",
|
||||||
|
position === "popper" &&
|
||||||
|
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
position={position}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<SelectScrollUpButton />
|
||||||
|
<SelectPrimitive.Viewport
|
||||||
|
className={cn(
|
||||||
|
"p-1",
|
||||||
|
position === "popper" &&
|
||||||
|
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</SelectPrimitive.Viewport>
|
||||||
|
<SelectScrollDownButton />
|
||||||
|
</SelectPrimitive.Content>
|
||||||
|
</SelectPrimitive.Portal>
|
||||||
|
))
|
||||||
|
SelectContent.displayName = SelectPrimitive.Content.displayName
|
||||||
|
|
||||||
|
const SelectLabel = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.Label>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<SelectPrimitive.Label
|
||||||
|
ref={ref}
|
||||||
|
className={cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
SelectLabel.displayName = SelectPrimitive.Label.displayName
|
||||||
|
|
||||||
|
const SelectItem = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.Item>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
|
||||||
|
>(({ className, children, ...props }, ref) => (
|
||||||
|
<SelectPrimitive.Item
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||||
|
<SelectPrimitive.ItemIndicator>
|
||||||
|
<Check className="h-4 w-4" />
|
||||||
|
</SelectPrimitive.ItemIndicator>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||||
|
</SelectPrimitive.Item>
|
||||||
|
))
|
||||||
|
SelectItem.displayName = SelectPrimitive.Item.displayName
|
||||||
|
|
||||||
|
const SelectSeparator = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.Separator>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<SelectPrimitive.Separator
|
||||||
|
ref={ref}
|
||||||
|
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
SelectSeparator.displayName = SelectPrimitive.Separator.displayName
|
||||||
|
|
||||||
|
export {
|
||||||
|
Select,
|
||||||
|
SelectGroup,
|
||||||
|
SelectValue,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectContent,
|
||||||
|
SelectLabel,
|
||||||
|
SelectItem,
|
||||||
|
SelectSeparator,
|
||||||
|
SelectScrollUpButton,
|
||||||
|
SelectScrollDownButton,
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
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-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
TableHead.displayName = "TableHead"
|
||||||
|
|
||||||
|
const TableCell = React.forwardRef<
|
||||||
|
HTMLTableCellElement,
|
||||||
|
React.TdHTMLAttributes<HTMLTableCellElement>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<td
|
||||||
|
ref={ref}
|
||||||
|
className={cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", 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,24 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
export interface TextareaProps
|
||||||
|
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
|
||||||
|
|
||||||
|
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||||
|
({ className, ...props }, ref) => {
|
||||||
|
return (
|
||||||
|
<textarea
|
||||||
|
className={cn(
|
||||||
|
"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
ref={ref}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Textarea.displayName = "Textarea"
|
||||||
|
|
||||||
|
export { Textarea }
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { type ClassValue, clsx } from "clsx"
|
||||||
|
import { twMerge } from "tailwind-merge"
|
||||||
|
|
||||||
|
export function cn(...inputs: ClassValue[]) {
|
||||||
|
return twMerge(clsx(inputs))
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { NextResponse } from 'next/server'
|
||||||
|
import type { NextRequest } from 'next/server'
|
||||||
|
|
||||||
|
// This function can be marked `async` if using `await` inside
|
||||||
|
export function middleware(request: NextRequest) {
|
||||||
|
|
||||||
|
let isAuth:any = request.cookies.get('isAuthAd')
|
||||||
|
|
||||||
|
try {
|
||||||
|
if(isAuth.value != "true"){
|
||||||
|
return NextResponse.redirect(new URL('/login', request.url))
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return NextResponse.redirect(new URL('/login', request.url))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export const config = {
|
||||||
|
matcher: [
|
||||||
|
/*
|
||||||
|
* Match all request paths except for the ones starting with:
|
||||||
|
* - api (API routes)
|
||||||
|
* - _next/static (static files)
|
||||||
|
* - _next/image (image optimization files)
|
||||||
|
* - favicon.ico (favicon file)
|
||||||
|
*/
|
||||||
|
'/((?!api|_next/static|_next/image|favicon.ico|login|login/verify|register).*)',
|
||||||
|
],
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||||
|
|
||||||
|
const queryClient = new QueryClient()
|
||||||
|
|
||||||
|
const ReactQueryProvider = ({children} : {children: React.ReactNode})=> {
|
||||||
|
return (
|
||||||
|
<QueryClientProvider client = {queryClient} >
|
||||||
|
{children}
|
||||||
|
</QueryClientProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default ReactQueryProvider
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
'use client'
|
||||||
|
import {useQuery, useMutation, useQueryClient} from "@tanstack/react-query";
|
||||||
|
import {getArzeshEmtiyaz} from "@/api/emtiyaz";
|
||||||
|
|
||||||
|
export const useGetArzeshEmtiyaz = () => {
|
||||||
|
return useQuery({queryKey: ['arzesh-emtiyaz'], queryFn: ()=>{ return getArzeshEmtiyaz() }})
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import {useQuery, useMutation, useQueryClient} from "@tanstack/react-query";
|
||||||
|
import {getMojri, getMojrian, updateMojriStatus} from "@/api/mojrian";
|
||||||
|
|
||||||
|
export const useGetMojrian = (status:string='WT') => {
|
||||||
|
return useQuery({queryKey: ['mojrian'], queryFn: ()=>{ return getMojrian(status) } },)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useGetMojri = (id:number) => {
|
||||||
|
return useQuery({queryKey: ['mojri', id], queryFn: ()=>{ return getMojri(id) } },)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useMojriStatusMutation = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
return useMutation({mutationFn: updateMojriStatus , onSuccess: ()=>{
|
||||||
|
queryClient.invalidateQueries({queryKey: ['mojri',]})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import {useMutation, useQuery, useQueryClient} from "@tanstack/react-query";
|
||||||
|
import {getOrderList, updateOrder, getOrder} from "@/api/order";
|
||||||
|
|
||||||
|
export const useGetOrder = (id:number) => {
|
||||||
|
return useQuery({queryKey: ['order', id], queryFn: ()=>{ return getOrder(id) } },)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useGetOrderList = (status:string='waiting') => {
|
||||||
|
return useQuery({queryKey: ['project-code-heads'], queryFn: ()=>{ return getOrderList(status) } },)
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
'use client'
|
||||||
|
import {useQuery, useMutation, useQueryClient} from "@tanstack/react-query";
|
||||||
|
import {addEmtiaz, getProject, getProjects} from "@/api/project";
|
||||||
|
|
||||||
|
export const useGetProjects = (projects_status:string = 'waiting') => {
|
||||||
|
return useQuery({queryKey: ['projects'], queryFn: ()=>{ return getProjects(projects_status) } },)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useGetProject = (id:number) => {
|
||||||
|
return useQuery({queryKey: ['project', id], queryFn: ()=>{ return getProject(id) } },)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useEmtiazMutation = () => {
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: addEmtiaz,
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({queryKey: ['project',]})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
'use client'
|
||||||
|
import { useRouter } from 'next/navigation'
|
||||||
|
import {useQuery, useMutation, useQueryClient} from "@tanstack/react-query";
|
||||||
|
import {createProjectCode, getProjectCodeHeads, getProjectCodes,} from "@/api/projectcode";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const useProjectCodeMutation = () => {
|
||||||
|
const router = useRouter()
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: createProjectCode,
|
||||||
|
onSuccess: (result) => {
|
||||||
|
console.log(result?.projectcode_id)
|
||||||
|
router.push(`/code/${result.projectcode_id}/`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useGetProjectCodes = (id:number, is_used:string='false') => {
|
||||||
|
return useQuery({queryKey: ['project-code-heads'], queryFn: ()=>{ return getProjectCodes(id, is_used) } },)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useGetProjectCodeHeads = () => {
|
||||||
|
return useQuery({queryKey: ['projectcodeheads1'], queryFn: ()=>{ return getProjectCodeHeads() } },)
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export interface IAddEmtiyaz {
|
||||||
|
emtiyaz: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export type TokenType = {
|
||||||
|
access: string;
|
||||||
|
refresh: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
interface IUserProfile {
|
||||||
|
codemeli: number
|
||||||
|
city: {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
ostan: {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
address: string
|
||||||
|
codeposti: number
|
||||||
|
ax_mojri: string | null
|
||||||
|
ax_meli: string | null
|
||||||
|
ax_fani: string | null
|
||||||
|
ax_sayer: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IMojrian {
|
||||||
|
id: number
|
||||||
|
mojri_status: string
|
||||||
|
name_family: string
|
||||||
|
mobile: number
|
||||||
|
uuid: string
|
||||||
|
user_profile: IUserProfile
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
export type ProjectType = {
|
||||||
|
id: number;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
address: string;
|
||||||
|
zirbana: number;
|
||||||
|
tabaghat: number;
|
||||||
|
vahed: number;
|
||||||
|
factor_price: number | null;
|
||||||
|
seller_name: string | null ;
|
||||||
|
seller_mobile: string | null;
|
||||||
|
seller_address: string | null;
|
||||||
|
status: string;
|
||||||
|
ax_factor: number | null;
|
||||||
|
cuser: number;
|
||||||
|
city: number;
|
||||||
|
op_cuser: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ICity {
|
||||||
|
id: number;
|
||||||
|
ostan: {
|
||||||
|
id: number;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
name: string;
|
||||||
|
is_ostan: boolean;
|
||||||
|
pv_id: null;
|
||||||
|
ostan: null;
|
||||||
|
};
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
name: string;
|
||||||
|
is_ostan: boolean;
|
||||||
|
pv_id: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IProject {
|
||||||
|
id: number;
|
||||||
|
city: ICity;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
address: string;
|
||||||
|
zirbana: number;
|
||||||
|
tabaghat: number;
|
||||||
|
vahed: number;
|
||||||
|
factor_price: number;
|
||||||
|
seller_name: null;
|
||||||
|
seller_mobile: null;
|
||||||
|
seller_address: null;
|
||||||
|
status: string;
|
||||||
|
ax_factor: null;
|
||||||
|
cuser: {
|
||||||
|
name_family: string;
|
||||||
|
mobile: number;
|
||||||
|
};
|
||||||
|
op_cuser: null;
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export const numberWithCommas = (x: number) => {
|
||||||
|
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||||
|
}
|
||||||
+73
-13
@@ -1,20 +1,80 @@
|
|||||||
import type { Config } from "tailwindcss";
|
import type { Config } from "tailwindcss"
|
||||||
|
|
||||||
const config: Config = {
|
const config = {
|
||||||
|
darkMode: ["class"],
|
||||||
content: [
|
content: [
|
||||||
"./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
|
'./pages/**/*.{ts,tsx}',
|
||||||
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
|
'./components/**/*.{ts,tsx}',
|
||||||
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
|
'./app/**/*.{ts,tsx}',
|
||||||
],
|
'./src/**/*.{ts,tsx}',
|
||||||
|
],
|
||||||
|
prefix: "",
|
||||||
theme: {
|
theme: {
|
||||||
|
container: {
|
||||||
|
center: true,
|
||||||
|
padding: "2rem",
|
||||||
|
screens: {
|
||||||
|
"2xl": "1400px",
|
||||||
|
},
|
||||||
|
},
|
||||||
extend: {
|
extend: {
|
||||||
backgroundImage: {
|
colors: {
|
||||||
"gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
|
border: "hsl(var(--border))",
|
||||||
"gradient-conic":
|
input: "hsl(var(--input))",
|
||||||
"conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
|
ring: "hsl(var(--ring))",
|
||||||
|
background: "hsl(var(--background))",
|
||||||
|
foreground: "hsl(var(--foreground))",
|
||||||
|
primary: {
|
||||||
|
DEFAULT: "hsl(var(--primary))",
|
||||||
|
foreground: "hsl(var(--primary-foreground))",
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
DEFAULT: "hsl(var(--secondary))",
|
||||||
|
foreground: "hsl(var(--secondary-foreground))",
|
||||||
|
},
|
||||||
|
destructive: {
|
||||||
|
DEFAULT: "hsl(var(--destructive))",
|
||||||
|
foreground: "hsl(var(--destructive-foreground))",
|
||||||
|
},
|
||||||
|
muted: {
|
||||||
|
DEFAULT: "hsl(var(--muted))",
|
||||||
|
foreground: "hsl(var(--muted-foreground))",
|
||||||
|
},
|
||||||
|
accent: {
|
||||||
|
DEFAULT: "hsl(var(--accent))",
|
||||||
|
foreground: "hsl(var(--accent-foreground))",
|
||||||
|
},
|
||||||
|
popover: {
|
||||||
|
DEFAULT: "hsl(var(--popover))",
|
||||||
|
foreground: "hsl(var(--popover-foreground))",
|
||||||
|
},
|
||||||
|
card: {
|
||||||
|
DEFAULT: "hsl(var(--card))",
|
||||||
|
foreground: "hsl(var(--card-foreground))",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
borderRadius: {
|
||||||
|
lg: "var(--radius)",
|
||||||
|
md: "calc(var(--radius) - 2px)",
|
||||||
|
sm: "calc(var(--radius) - 4px)",
|
||||||
|
},
|
||||||
|
keyframes: {
|
||||||
|
"accordion-down": {
|
||||||
|
from: { height: "0" },
|
||||||
|
to: { height: "var(--radix-accordion-content-height)" },
|
||||||
|
},
|
||||||
|
"accordion-up": {
|
||||||
|
from: { height: "var(--radix-accordion-content-height)" },
|
||||||
|
to: { height: "0" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
animation: {
|
||||||
|
"accordion-down": "accordion-down 0.2s ease-out",
|
||||||
|
"accordion-up": "accordion-up 0.2s ease-out",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [],
|
plugins: [require("tailwindcss-animate")],
|
||||||
};
|
} satisfies Config
|
||||||
export default config;
|
|
||||||
|
export default config
|
||||||
Reference in new issue
Block a user