diff --git a/.env b/.env new file mode 100644 index 0000000..42723dc --- /dev/null +++ b/.env @@ -0,0 +1 @@ +NEXT_PUBLIC_BASE_URL=https://api.d.aiengines.ir/rasad/v1 diff --git a/.gitignore b/.gitignore index 5ef6a52..23bad85 100644 --- a/.gitignore +++ b/.gitignore @@ -31,7 +31,7 @@ yarn-error.log* .pnpm-debug.log* # env files (can opt-in for committing if needed) -.env* +.env*.local # vercel .vercel diff --git a/components/base/global.js b/components/base/global.js new file mode 100644 index 0000000..417198b --- /dev/null +++ b/components/base/global.js @@ -0,0 +1,15 @@ +import { Global } from "@emotion/react"; + +export const Fonts = () => ( + +); diff --git a/contexts/KeycloakContext.js b/contexts/KeycloakContext.js new file mode 100644 index 0000000..f1c9842 --- /dev/null +++ b/contexts/KeycloakContext.js @@ -0,0 +1,36 @@ +import keycloak from "@/lib/keycloak"; +import { createContext, useContext, useEffect, useState } from "react"; + +const KeycloakContext = createContext(); + +let keycloakInitialized = false; + +export const KeycloakProvider = ({ children }) => { + const [initialized, setInitialized] = useState(false); + const [authenticated, setAuthenticated] = useState(false); + + useEffect(() => { + if (!keycloakInitialized) { + keycloakInitialized = true; + keycloak + .init({ + onLoad: "login-required", + checkLoginIframe: false, + flow: "implicit", + }) + .then((auth) => { + setAuthenticated(auth); + setInitialized(true); + }) + .catch((err) => {}); + } + }, []); + + return ( + + {children} + + ); +}; + +export const useKeycloak = () => useContext(KeycloakContext); diff --git a/lib/api.js b/lib/api.js new file mode 100644 index 0000000..6e4f5b9 --- /dev/null +++ b/lib/api.js @@ -0,0 +1,54 @@ +import axios from "axios"; +import keycloak from "./keycloak"; + +export const baseUrl = process.env.NEXT_PUBLIC_BASE_URL; + +const axiosInstance = axios.create({ + baseURL: baseUrl, +}); + +axiosInstance.interceptors.request.use( + async (config) => { + // if (keycloak?.authenticated) { + // config.headers.Authorization = `Bearer ${keycloak.token}`; + // await keycloak.updateToken(30); + // } + return config; + }, + (error) => Promise.reject(error), +); + +axiosInstance.interceptors.response.use( + (response) => response, + async (error) => { + const originalRequest = error.config; + + // if (error?.response?.status === 401 && !originalRequest._retry) { + // originalRequest._retry = true; + // keycloak.login(); + // try { + // await keycloak.updateToken(30); + // const newToken = keycloak.token; + + // if (newToken) { + // originalRequest.headers["Authorization"] = `Bearer ${newToken}`; + // return axiosInstance(originalRequest); + // } + // } catch (refreshError) { + // localStorage.removeItem("access_account"); + // keycloak.logout({ redirectUri: window.location.origin }); + // } + // } + + return Promise.reject(error); + }, +); + +// ✅ Fetcher for GET (used in SWR) +export const fetcher = async (url) => { + const fullUrl = url.startsWith("http") ? url : `${baseUrl}${url}`; + const resp = await axiosInstance.get(fullUrl); + return resp.data; +}; + +export default axiosInstance; diff --git a/lib/keycloak.js b/lib/keycloak.js new file mode 100644 index 0000000..a7fa485 --- /dev/null +++ b/lib/keycloak.js @@ -0,0 +1,16 @@ +import Keycloak from "keycloak-js"; + +const keycloak = new Keycloak({ + url: "https://auth.ibagher.ir", + realm: "bi", + clientId: "rasad", +}); + +export const initKeycloak = () => + keycloak.init({ + onLoad: "login-required", + checkLoginIframe: false, // optional + flow: "implicit", // You can change this to 'standard' if you use authorization code flow + }); + +export default keycloak; diff --git a/package.json b/package.json index cf23b0b..064b3c9 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,9 @@ "@chakra-ui/react": "2", "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", + "axios": "^1.13.5", "framer-motion": "^12.34.3", + "keycloak-js": "^26.2.3", "next": "16.1.6", "next-query-params": "^5.1.0", "react": "19.2.3", diff --git a/pages/_app.js b/pages/_app.js index 1b364eb..cd6662d 100644 --- a/pages/_app.js +++ b/pages/_app.js @@ -3,17 +3,30 @@ import { ChakraProvider } from "@chakra-ui/react"; import { QueryParamProvider } from "use-query-params"; import { NextAdapter } from "next-query-params"; import { theme } from "@/components/theme"; +import { useKeycloak } from "@/contexts/KeycloakContext"; +import { SWRConfig } from "swr"; +import { fetcher } from "@/lib/api"; +import { Fonts } from "@/components/base/global"; + +const Adapter = (props) => ; export default function App({ Component, pageProps }) { - const Adapter = (props) => ; + // const { initialized, authenticated } = useKeycloak(); + + // if (!initialized) return ; + // if (!authenticated) return
Redirecting to login...
; return ( - - + + + - + ); } diff --git a/pages/_document.js b/pages/_document.js index b2fff8b..81db55d 100644 --- a/pages/_document.js +++ b/pages/_document.js @@ -3,7 +3,10 @@ import { Html, Head, Main, NextScript } from "next/document"; export default function Document() { return ( - + + سامانه جامع تولید محتوای هوشمند + +
diff --git a/pages/index.js b/pages/index.js index 59d510c..cdebb2f 100644 --- a/pages/index.js +++ b/pages/index.js @@ -12,18 +12,10 @@ import { TabPanel, TabPanels, Icon, - Divider, HStack, Image, - Stack, } from "@chakra-ui/react"; -import { - FiFileText, - FiImage, - FiVideo, - FiLayers, - FiSettings, -} from "react-icons/fi"; +import { FiImage, FiLayers } from "react-icons/fi"; import { CiVideoOn } from "react-icons/ci"; import { IoDocumentTextOutline, @@ -31,7 +23,6 @@ import { IoVideocamOutline, } from "react-icons/io5"; import { IoIosGitMerge } from "react-icons/io"; - import { NumberParam, StringParam, @@ -39,7 +30,6 @@ import { withDefault, } from "use-query-params"; import { BsChatText } from "react-icons/bs"; -// import { StringParam, useQueryParams, withDefault } from "use-query-params"; export default function Home() { const [filters, setFilters] = useQueryParams({ @@ -49,174 +39,153 @@ export default function Home() { }); return ( - - {/* Main Content */} - - - {/* Brand / Title */} - - - سرویس ها - - - داشبورد تولید محتوا - - + + {/* Header */} + - - - {/* Menu */} - setFilters({ model_name: e })} - index={filters?.model_name} - > - - خانم ستاری - رکن آبادی - - - - - - - - - - - - - - - - - - - - - - - - - - - {/* Footer */} - - - - + {/* Page Layout */} + + {/* Sidebar */} - - - - موسسه تولید سیستم های خبره و هوشمند اسلامی باقرالعلوم(ع) - + + {/* Menu */} + setFilters({ model_name: e })} + index={filters?.model_name} + > + + خانم ستاری + رکن آبادی + + + + + + + + + + + + + + + + + + + + + + + + + + + {/* Footer */} - + + {/* Content */} + - - - {/* Right Sidebar */} + ); } -function SidebarItem({ - icon, - label, - active = false, - filters, - setFilters, - name, -}) { +function AppHeader() { + return ( + + + + + + سامانه تولید محتوای هوشمند + + + سامانه جامع تولید محتوا با استفاده از مدل‌های زبانی و مولد تصویر و + ویدئو + + + + + + + موسسه تولید سیستم های خبره و هوشمند اسلامی باقرالعلوم(ع) + + + + ); +} + +function SidebarItem({ icon, label, active = false, setFilters, name }) { return (