diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..2426118 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,42 @@ +kind: pipeline +type: ssh +name: silancar-build-deploy + +server: + host: + from_secret: ssh_host + user: + from_secret: ssh_user + ssh_key: + from_secret: ssh_key + +steps: + - name: prepare repo + when: + branch: + - main + commands: + - rm -rf /opt/build/silancar + - mkdir -p /opt/build + - cd /opt/build + - git clone http://38.47.180.165:3000/humas/silancar.git + + - name: build image + when: + branch: + - main + commands: + - docker login 38.47.180.165:3000 -u administrator -p HarborDockerImageRep0 + - cd /opt/build/silancar + - docker build -t 38.47.180.165:3000/humas/silancar:$DRONE_BRANCH . + - docker push 38.47.180.165:3000/humas/silancar:$DRONE_BRANCH + + - name: deploy + when: + branch: + - main + commands: + - docker pull 38.47.180.165:3000/humas/silancar:$DRONE_BRANCH + - docker stop web-silancar|| true + - docker rm web-silancar || true + - docker run -dt -p 4700:4000 --restart always --name web-silancar 38.47.180.165:3000/humas/silancar:$DRONE_BRANCH diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..5fc7ef3 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,34 @@ +FROM node:23.5.0-alpine + +ENV PORT=4000 +ENV NODE_ENV=production +ENV NODE_OPTIONS="--max-old-space-size=4096" + +RUN apk add --no-cache \ + python3 \ + make \ + g++ \ + git \ + sqlite-dev + +WORKDIR /usr/src/app + +# Copy dependency files +COPY package.json package-lock.json ./ + +# Install dependencies +RUN npm install --legacy-peer-deps + +# Copy source code +COPY . . + +# Init DB (aman karena pakai || true) +RUN mkdir -p ./lib/db +RUN node scripts/init-db.js || true + +# Build Next.js +RUN npm run build + +EXPOSE 4000 + +CMD ["npm", "run", "start"] diff --git a/app/auth/sign-in/page.tsx b/app/auth/sign-in/page.tsx index f0442f7..51c7258 100644 --- a/app/auth/sign-in/page.tsx +++ b/app/auth/sign-in/page.tsx @@ -5,6 +5,7 @@ import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import Link from "next/link" import { useRouter } from "next/navigation" +import { setCookiesEncrypt } from "@/utils/globals" type FormValues = { nrp: string @@ -26,11 +27,14 @@ export default function SignInPage() { }) const onSubmit = async (data: FormValues) => { - console.log("DATA LOGIN:", data) await new Promise((res) => setTimeout(res, 1000)) + if(data.nrp=="12345678"&&data.password=="P@ssw0rd.1") { + setCookiesEncrypt("status", "Login", { expires: 1 }); + router.push("/dashboard") + } + - router.push("/dashboard") } return ( diff --git a/app/dashboard/page.tsx b/app/dashboard/page.tsx index a98bc5c..88c2187 100644 --- a/app/dashboard/page.tsx +++ b/app/dashboard/page.tsx @@ -1,8 +1,11 @@ +'use client' import DashboardSideMenu from "@/components/layout/dashboard-side-menu" import Footer from "@/components/layout/footer" -import { PinIcon } from "lucide-react" +import { getCookiesDecrypt } from "@/utils/globals" import Image from "next/image" import Link from "next/link" +import { useRouter } from "next/navigation" +import { useEffect } from "react" const dummy = { name: "Andri2 Ferinata", plat: "B 14 QU" } @@ -19,6 +22,15 @@ const menu = [ ] export default function Dashboard() { + const login=getCookiesDecrypt("status") + const router=useRouter() + + useEffect(()=>{ + if(!login){ + router.push("/auth/sign-in") + } + },[login,router]) + return (
diff --git a/app/favicon.ico b/app/favicon.ico index 718d6fe..ae69595 100644 Binary files a/app/favicon.ico and b/app/favicon.ico differ diff --git a/app/layout.tsx b/app/layout.tsx index f6e8f18..1f9a9f5 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -3,6 +3,15 @@ import { Geist_Mono, Inter, Roboto } from "next/font/google" import "./globals.css" import { ThemeProvider } from "@/components/theme-provider" import { cn } from "@/lib/utils" +import type { Metadata } from "next" + +export const metadata: Metadata = { + title: "Silancar", + description: "Silancar Korlantas", + icons: { + icon: "/favicon.ico", // atau png + }, +} const inter = Inter({ subsets: ["latin"], variable: "--font-sans" }) diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000..ae69595 Binary files /dev/null and b/favicon.ico differ diff --git a/package-lock.json b/package-lock.json index 7d4c879..e5c8048 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,9 +8,13 @@ "name": "silancar", "version": "0.0.1", "dependencies": { + "@types/crypto-js": "^4.2.2", + "@types/js-cookie": "^3.0.6", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "crypto-js": "^4.2.0", "embla-carousel-react": "^8.6.0", + "js-cookie": "^3.0.5", "lucide-react": "^0.577.0", "next": "16.1.7", "next-themes": "^0.4.6", @@ -3545,12 +3549,22 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/crypto-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.2.tgz", + "integrity": "sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==" + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true }, + "node_modules/@types/js-cookie": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-3.0.6.tgz", + "integrity": "sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==" + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -4939,6 +4953,11 @@ "node": ">= 8" } }, + "node_modules/crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -7305,6 +7324,14 @@ "url": "https://github.com/sponsors/panva" } }, + "node_modules/js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "engines": { + "node": ">=14" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", diff --git a/package.json b/package.json index 272fd69..30af693 100644 --- a/package.json +++ b/package.json @@ -12,9 +12,13 @@ "typecheck": "tsc --noEmit" }, "dependencies": { + "@types/crypto-js": "^4.2.2", + "@types/js-cookie": "^3.0.6", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "crypto-js": "^4.2.0", "embla-carousel-react": "^8.6.0", + "js-cookie": "^3.0.5", "lucide-react": "^0.577.0", "next": "16.1.7", "next-themes": "^0.4.6", diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..ae69595 Binary files /dev/null and b/public/favicon.ico differ diff --git a/utils/globals.tsx b/utils/globals.tsx new file mode 100644 index 0000000..311028a --- /dev/null +++ b/utils/globals.tsx @@ -0,0 +1,37 @@ +import Cookies from "js-cookie" +import CryptoJS from "crypto-js" + +export function setCookiesEncrypt( + param: string, + data: T, + options?: Cookies.CookieAttributes +) { + const cookiesEncrypt = CryptoJS.AES.encrypt( + JSON.stringify(data), + `${param}_EncryptKey@silancar` + ).toString() + + Cookies.set(param, cookiesEncrypt, options) +} + +export function getCookiesDecrypt(param: string): T | null { + const cookiesEncrypt = Cookies.get(param) + + try { + if (cookiesEncrypt) { + const bytes = CryptoJS.AES.decrypt( + cookiesEncrypt, + `${param}_EncryptKey@silancar` + ) + + const decrypted = bytes.toString(CryptoJS.enc.Utf8) + + return JSON.parse(decrypted) as T + } + + return null + } catch (e) { + console.error("Decrypt error:", e) + return null + } +} \ No newline at end of file