mirror of
https://github.com/Ategon/Jamjar.git
synced 2025-02-12 06:16:21 +00:00
Compare commits
8 commits
c204a54815
...
2178675f2a
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2178675f2a | ||
![]() |
aaa9305c09 | ||
![]() |
fc5de7ba12 | ||
![]() |
3a2d5b1cb3 | ||
![]() |
ad7311247b | ||
![]() |
51d92b2fc4 | ||
![]() |
e61dd263c5 | ||
![]() |
2c05a7464f |
12 changed files with 405 additions and 22 deletions
25
package-lock.json
generated
25
package-lock.json
generated
|
@ -15,7 +15,8 @@
|
||||||
"lucide-react": "^0.453.0",
|
"lucide-react": "^0.453.0",
|
||||||
"next": "15.0.1",
|
"next": "15.0.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0"
|
"react-dom": "^18.2.0",
|
||||||
|
"react-toastify": "^11.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
|
@ -7605,6 +7606,28 @@
|
||||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-toastify": {
|
||||||
|
"version": "11.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-11.0.3.tgz",
|
||||||
|
"integrity": "sha512-cbPtHJPfc0sGqVwozBwaTrTu1ogB9+BLLjd4dDXd863qYLj7DGrQ2sg5RAChjFUB4yc3w8iXOtWcJqPK/6xqRQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"clsx": "^2.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^18 || ^19",
|
||||||
|
"react-dom": "^18 || ^19"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-toastify/node_modules/clsx": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/read-cache": {
|
"node_modules/read-cache": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||||
|
|
|
@ -16,7 +16,8 @@
|
||||||
"lucide-react": "^0.453.0",
|
"lucide-react": "^0.453.0",
|
||||||
"next": "15.0.1",
|
"next": "15.0.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0"
|
"react-dom": "^18.2.0",
|
||||||
|
"react-toastify": "^11.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
|
|
BIN
public/images/dare2jam.png
Normal file
BIN
public/images/dare2jam.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 25 KiB |
Binary file not shown.
Before ![]() (image error) Size: 56 KiB |
|
@ -3,11 +3,12 @@ import { Inter } from "next/font/google";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
import Navbar from "../components/navbar";
|
import Navbar from "../components/navbar";
|
||||||
import Providers from "./providers";
|
import Providers from "./providers";
|
||||||
|
import { ToastContainer } from "react-toastify";
|
||||||
|
|
||||||
const inter = Inter({ subsets: ["latin"] });
|
const inter = Inter({ subsets: ["latin"] });
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Edikoyo Jam",
|
title: "Dare2Jam",
|
||||||
description: "A community built game jam!",
|
description: "A community built game jam!",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -24,6 +25,7 @@ export default function RootLayout({
|
||||||
<div className="bg-zinc-100 dark:bg-zinc-950 min-h-screen">
|
<div className="bg-zinc-100 dark:bg-zinc-950 min-h-screen">
|
||||||
<Navbar />
|
<Navbar />
|
||||||
<div className="max-w-8xl mx-auto">{children}</div>
|
<div className="max-w-8xl mx-auto">{children}</div>
|
||||||
|
<ToastContainer />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Providers>
|
</Providers>
|
||||||
|
|
100
src/app/login/page.tsx
Normal file
100
src/app/login/page.tsx
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { Button, Form, Input } from "@nextui-org/react";
|
||||||
|
import { redirect } from "next/navigation";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { toast } from "react-toastify";
|
||||||
|
|
||||||
|
export default function UserPage() {
|
||||||
|
const [username, setUsername] = useState("");
|
||||||
|
const [password, setPassword] = useState("");
|
||||||
|
const [errors, setErrors] = useState({});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="absolute flex items-center justify-center top-0 left-0 w-screen h-screen">
|
||||||
|
<Form
|
||||||
|
className="w-full max-w-xs flex flex-col gap-4"
|
||||||
|
validationErrors={errors}
|
||||||
|
onReset={() => {
|
||||||
|
setUsername("");
|
||||||
|
setPassword("");
|
||||||
|
}}
|
||||||
|
onSubmit={async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (!username && !password) {
|
||||||
|
setErrors({
|
||||||
|
username: "Please enter a valid username",
|
||||||
|
password: "Please enter a valid password",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!username) {
|
||||||
|
setErrors({ username: "Please enter a valid username" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!password) {
|
||||||
|
setErrors({ password: "Please enter a valid password" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(
|
||||||
|
process.env.NEXT_PUBLIC_MODE === "PROD"
|
||||||
|
? "https://d2jam.com/api/v1/login"
|
||||||
|
: "http://localhost:3005/api/v1/login",
|
||||||
|
{
|
||||||
|
body: JSON.stringify({ username: username, password: password }),
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.status == 401) {
|
||||||
|
setErrors({ password: "Invalid username or password" });
|
||||||
|
setPassword("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const token = await response.json();
|
||||||
|
document.cookie = `token=${token}`;
|
||||||
|
|
||||||
|
toast.success("Successfully logged in");
|
||||||
|
|
||||||
|
redirect("/");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
isRequired
|
||||||
|
label="Username"
|
||||||
|
labelPlacement="outside"
|
||||||
|
name="username"
|
||||||
|
placeholder="Enter your username"
|
||||||
|
type="text"
|
||||||
|
value={username}
|
||||||
|
onValueChange={setUsername}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
isRequired
|
||||||
|
label="Password"
|
||||||
|
labelPlacement="outside"
|
||||||
|
name="password"
|
||||||
|
placeholder="Enter your password"
|
||||||
|
type="password"
|
||||||
|
value={password}
|
||||||
|
onValueChange={setPassword}
|
||||||
|
/>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Button color="primary" type="submit">
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
<Button type="reset" variant="flat">
|
||||||
|
Reset
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
21
src/app/logout/page.tsx
Normal file
21
src/app/logout/page.tsx
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { redirect } from "next/navigation";
|
||||||
|
import React, { useEffect } from "react";
|
||||||
|
import { toast } from "react-toastify";
|
||||||
|
|
||||||
|
export default function UserPage() {
|
||||||
|
useEffect(() => {
|
||||||
|
document.cookie = "token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
|
||||||
|
|
||||||
|
toast.success("Successfully logged out");
|
||||||
|
|
||||||
|
redirect("/");
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="absolute flex items-center justify-center top-0 left-0 w-screen h-screen">
|
||||||
|
<p>Logging out...</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
import { Image } from "@nextui-org/image";
|
import { Image } from "@nextui-org/image";
|
||||||
import { Button } from "@nextui-org/button";
|
import { Button } from "@nextui-org/button";
|
||||||
import { SiDiscord } from "@icons-pack/react-simple-icons";
|
import { SiDiscord } from "@icons-pack/react-simple-icons";
|
||||||
|
import { Link } from "@nextui-org/react";
|
||||||
|
|
||||||
export default async function Home() {
|
export default async function Home() {
|
||||||
return (
|
return (
|
||||||
|
@ -19,14 +20,10 @@ export default async function Home() {
|
||||||
<div className="relative left-0 top-0 z-10 px-8">
|
<div className="relative left-0 top-0 z-10 px-8">
|
||||||
<div className="flex gap-20">
|
<div className="flex gap-20">
|
||||||
<div className="flex flex-col gap-4 py-16 sm:py-36 md:py-72">
|
<div className="flex flex-col gap-4 py-16 sm:py-36 md:py-72">
|
||||||
<h1 className="text-3xl sm:text-4xl md:text-5xl">Edikoyo Jam</h1>
|
<h1 className="text-3xl sm:text-4xl md:text-5xl">Dare2Jam</h1>
|
||||||
<p className="text-lg sm:text-xl">April 4th - 7th</p>
|
<p className="text-lg sm:text-xl">April 4th - 7th</p>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<a
|
<Link href="https://discord.gg/rfmKzM6ASw" target="_blank">
|
||||||
href="https://discord.gg/rfmKzM6ASw"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<Button
|
<Button
|
||||||
variant="bordered"
|
variant="bordered"
|
||||||
className="border-white/50 text-white"
|
className="border-white/50 text-white"
|
||||||
|
@ -34,7 +31,7 @@ export default async function Home() {
|
||||||
>
|
>
|
||||||
Join the Discord
|
Join the Discord
|
||||||
</Button>
|
</Button>
|
||||||
</a>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
124
src/app/signup/page.tsx
Normal file
124
src/app/signup/page.tsx
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { Button, Form, Input } from "@nextui-org/react";
|
||||||
|
import { redirect } from "next/navigation";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { toast } from "react-toastify";
|
||||||
|
|
||||||
|
export default function UserPage() {
|
||||||
|
const [username, setUsername] = useState("");
|
||||||
|
const [password, setPassword] = useState("");
|
||||||
|
const [password2, setPassword2] = useState("");
|
||||||
|
const [errors, setErrors] = useState({});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="absolute flex items-center justify-center top-0 left-0 w-screen h-screen">
|
||||||
|
<Form
|
||||||
|
className="w-full max-w-xs flex flex-col gap-4"
|
||||||
|
validationErrors={errors}
|
||||||
|
onReset={() => {
|
||||||
|
setUsername("");
|
||||||
|
setPassword("");
|
||||||
|
setPassword2("");
|
||||||
|
}}
|
||||||
|
onSubmit={async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (!password || !username || !password2) {
|
||||||
|
const localErrors: Record<string, string> = {};
|
||||||
|
|
||||||
|
if (password && password.length < 8) {
|
||||||
|
setPassword2("");
|
||||||
|
setErrors({ password: "Password must be minimum 8 characters" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!password) {
|
||||||
|
localErrors["password"] = "Please enter a valid password";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!password2) {
|
||||||
|
localErrors["password2"] = "Please reenter your password";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!username) {
|
||||||
|
localErrors["username"] = "Please enter a valid username";
|
||||||
|
}
|
||||||
|
setErrors(localErrors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (password.length < 8) {
|
||||||
|
setPassword2("");
|
||||||
|
setErrors({ password: "Password must be minimum 8 characters" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (password != password2) {
|
||||||
|
setPassword2("");
|
||||||
|
setErrors({ password2: "Passwords do not match" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(
|
||||||
|
process.env.NEXT_PUBLIC_MODE === "PROD"
|
||||||
|
? "https://d2jam.com/api/v1/signup"
|
||||||
|
: "http://localhost:3005/api/v1/signup",
|
||||||
|
{
|
||||||
|
body: JSON.stringify({ username: username, password: password }),
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const token = await response.json();
|
||||||
|
document.cookie = `token=${token}`;
|
||||||
|
|
||||||
|
toast.success("Successfully signed up");
|
||||||
|
|
||||||
|
redirect("/");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
isRequired
|
||||||
|
label="Username"
|
||||||
|
labelPlacement="outside"
|
||||||
|
name="username"
|
||||||
|
placeholder="Enter your username"
|
||||||
|
type="text"
|
||||||
|
value={username}
|
||||||
|
onValueChange={setUsername}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
isRequired
|
||||||
|
label="Password"
|
||||||
|
labelPlacement="outside"
|
||||||
|
name="password"
|
||||||
|
placeholder="Enter your password"
|
||||||
|
type="password"
|
||||||
|
value={password}
|
||||||
|
onValueChange={setPassword}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
isRequired
|
||||||
|
label="Password Confirmation"
|
||||||
|
labelPlacement="outside"
|
||||||
|
name="password2"
|
||||||
|
placeholder="Reenter your password"
|
||||||
|
type="password"
|
||||||
|
value={password2}
|
||||||
|
onValueChange={setPassword2}
|
||||||
|
/>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Button color="primary" type="submit">
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
<Button type="reset" variant="flat">
|
||||||
|
Reset
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Navbar as NavbarBase,
|
Navbar as NavbarBase,
|
||||||
NavbarBrand,
|
NavbarBrand,
|
||||||
|
@ -6,10 +8,51 @@ import {
|
||||||
} from "@nextui-org/navbar";
|
} from "@nextui-org/navbar";
|
||||||
import { Link } from "@nextui-org/link";
|
import { Link } from "@nextui-org/link";
|
||||||
import { Divider } from "@nextui-org/divider";
|
import { Divider } from "@nextui-org/divider";
|
||||||
import { Image, Tooltip } from "@nextui-org/react";
|
import {
|
||||||
|
Avatar,
|
||||||
|
Button,
|
||||||
|
Dropdown,
|
||||||
|
DropdownItem,
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownTrigger,
|
||||||
|
Image,
|
||||||
|
Tooltip,
|
||||||
|
} from "@nextui-org/react";
|
||||||
import { SiDiscord, SiForgejo, SiGithub } from "@icons-pack/react-simple-icons";
|
import { SiDiscord, SiForgejo, SiGithub } from "@icons-pack/react-simple-icons";
|
||||||
|
import { LogInIcon, NotebookPen } from "lucide-react";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { hasCookie, getCookies } from "@/helpers/cookie";
|
||||||
|
import { usePathname } from "next/navigation";
|
||||||
|
|
||||||
export default function Navbar() {
|
export default function Navbar() {
|
||||||
|
const [user, setUser] = useState("");
|
||||||
|
const pathname = usePathname();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
loadUser();
|
||||||
|
async function loadUser() {
|
||||||
|
if (!hasCookie()) {
|
||||||
|
setUser("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(
|
||||||
|
process.env.NEXT_PUBLIC_MODE === "PROD"
|
||||||
|
? "https://d2jam.com/api/v1/self"
|
||||||
|
: "http://localhost:3005/api/v1/self",
|
||||||
|
{
|
||||||
|
headers: { authorization: `Bearer ${getCookies().token}` },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if ((await response.text()) == "ok") {
|
||||||
|
setUser("ok");
|
||||||
|
} else {
|
||||||
|
setUser("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [pathname]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NavbarBase
|
<NavbarBase
|
||||||
shouldHideOnScroll
|
shouldHideOnScroll
|
||||||
|
@ -21,7 +64,7 @@ export default function Navbar() {
|
||||||
href="/"
|
href="/"
|
||||||
className="duration-500 ease-in-out transition-all transform hover:scale-110"
|
className="duration-500 ease-in-out transition-all transform hover:scale-110"
|
||||||
>
|
>
|
||||||
<Image src="/images/edikoyo.png" alt="Edikoyo logo" width={160} />
|
<Image src="/images/dare2jam.png" alt="Dare2Jam logo" width={80} />
|
||||||
</Link>
|
</Link>
|
||||||
</NavbarBrand>
|
</NavbarBrand>
|
||||||
<NavbarContent>
|
<NavbarContent>
|
||||||
|
@ -83,15 +126,63 @@ export default function Navbar() {
|
||||||
</Link>
|
</Link>
|
||||||
</NavbarItem>
|
</NavbarItem>
|
||||||
<Divider orientation="vertical" className="h-1/2" />
|
<Divider orientation="vertical" className="h-1/2" />
|
||||||
{/* <NavbarItem>
|
{!user ? (
|
||||||
<Button
|
<div className="flex gap-3 items-center">
|
||||||
endContent={<LogInIcon />}
|
<NavbarItem>
|
||||||
className="text-white border-white/50 hover:border-green-100/50 hover:text-green-100 hover:scale-110 transition-all transform duration-500 ease-in-out"
|
<Link href="/login">
|
||||||
variant="bordered"
|
<Button
|
||||||
>
|
endContent={<LogInIcon />}
|
||||||
Log In
|
className="text-white border-white/50 hover:border-green-100/50 hover:text-green-100 hover:scale-110 transition-all transform duration-500 ease-in-out"
|
||||||
</Button>
|
variant="bordered"
|
||||||
</NavbarItem> */}
|
>
|
||||||
|
Log In
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</NavbarItem>
|
||||||
|
<NavbarItem>
|
||||||
|
<Link href="/signup">
|
||||||
|
<Button
|
||||||
|
endContent={<NotebookPen />}
|
||||||
|
className="text-white border-white/50 hover:border-green-100/50 hover:text-green-100 hover:scale-110 transition-all transform duration-500 ease-in-out"
|
||||||
|
variant="bordered"
|
||||||
|
>
|
||||||
|
Sign up
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</NavbarItem>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<Dropdown>
|
||||||
|
<DropdownTrigger>
|
||||||
|
<Avatar />
|
||||||
|
</DropdownTrigger>
|
||||||
|
<DropdownMenu>
|
||||||
|
{/* <DropdownItem
|
||||||
|
key="profile"
|
||||||
|
className="text-black"
|
||||||
|
href="/profile"
|
||||||
|
>
|
||||||
|
Profile
|
||||||
|
</DropdownItem>
|
||||||
|
<DropdownItem
|
||||||
|
showDivider
|
||||||
|
key="settings"
|
||||||
|
className="text-black"
|
||||||
|
href="/settings"
|
||||||
|
>
|
||||||
|
Settings
|
||||||
|
</DropdownItem> */}
|
||||||
|
<DropdownItem
|
||||||
|
key="logout"
|
||||||
|
color="danger"
|
||||||
|
className="text-danger"
|
||||||
|
href="/logout"
|
||||||
|
>
|
||||||
|
Logout
|
||||||
|
</DropdownItem>
|
||||||
|
</DropdownMenu>
|
||||||
|
</Dropdown>
|
||||||
|
)}
|
||||||
</NavbarContent>
|
</NavbarContent>
|
||||||
</NavbarBase>
|
</NavbarBase>
|
||||||
);
|
);
|
||||||
|
|
|
@ -9,7 +9,11 @@ export default function Posts() {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchPosts = async () => {
|
const fetchPosts = async () => {
|
||||||
const response = await fetch("https://jam.edikoyo.com/api/v1/posts");
|
const response = await fetch(
|
||||||
|
process.env.NEXT_PUBLIC_MODE === "PROD"
|
||||||
|
? "https://d2jam.com/api/v1/posts"
|
||||||
|
: "http://localhost:3005/api/v1/posts"
|
||||||
|
);
|
||||||
setPosts(await response.json());
|
setPosts(await response.json());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
20
src/helpers/cookie.ts
Normal file
20
src/helpers/cookie.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
export function getCookies() {
|
||||||
|
const pairs = document.cookie.split(";");
|
||||||
|
const cookies: Record<string, string> = {};
|
||||||
|
for (let i = 0; i < pairs.length; i++) {
|
||||||
|
const pair = pairs[i].split("=");
|
||||||
|
cookies[(pair[0] + "").trim()] = unescape(pair.slice(1).join("="));
|
||||||
|
}
|
||||||
|
return cookies;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hasCookie() {
|
||||||
|
const pairs = document.cookie.split(";");
|
||||||
|
for (let i = 0; i < pairs.length; i++) {
|
||||||
|
const pair = pairs[i].split("=");
|
||||||
|
if (pair[0] == "token") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
Loading…
Reference in a new issue