Skip to content

Commit

Permalink
Merge pull request #1 from arnavrneo/nextjs-shift
Browse files Browse the repository at this point in the history
Frontend + Go backend
  • Loading branch information
arnavrneo authored Jan 26, 2024
2 parents 151405e + d7d1a7e commit 75e8cc1
Show file tree
Hide file tree
Showing 35 changed files with 658 additions and 350 deletions.
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
*.env
*.air.toml
*tmp
frontend/.next
frontend/node_modules
*.next
*node_modules
1 change: 0 additions & 1 deletion README.md

This file was deleted.

103 changes: 96 additions & 7 deletions url-shortener/frontend/app/main/page.jsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,98 @@
import React from 'react'
"use client";

import React, {useEffect, useState} from 'react'
import FourOOne from "@/pages/Unauthorized";
import {useRouter} from "next/navigation";

function Main() {
const [userName, setUserName] = useState('');
const [logged, setLogged] = useState(false);
const [url, setUrl] = useState('');
const [visible, setVisible] = useState(false);
const [shortLink, setShortLink] = useState('');

const router = useRouter();

useEffect(() => {
(
async () => {
const response = await fetch(process.env.NEXT_PUBLIC_ENDPOINT + '/user', {
credentials: 'include',
headers: {"Content-Type": "application/json"},
});

if (response.ok) {
const content = await response.json();
setUserName(content.username);
setLogged(true)
} else {
setLogged(false)
}
}
)();
}, []);


const handleShorten = async (e) => {
e.preventDefault();

const formData = new FormData();
formData.append("url", url);

try {
const response = await fetch(process.env.NEXT_PUBLIC_ENDPOINT + "/shorten", {
method: "POST",
credentials: "include",
// headers: {"Content-Type": "application/json"},
body: formData,
})

if (response.ok) {
const data = await response.json()
console.log(data)
setShortLink(data.shorten_link)
setVisible(true)
} else {
alert("url cannot be sent")
}
} catch (error) {
console.log(error);
}
}

const handleLogout = async () => {
try {
const response = await fetch(process.env.NEXT_PUBLIC_ENDPOINT + "/logout", {
credentials: "include",
method: "POST",
})

if (response.ok) {
console.log("logged out successfully")
router.push("/")
}
} catch (error) {
console.log(error)
}
}

function Page() {
return (
<div>
<div className="flex flex-wrap min-h-screen w-full content-center justify-center bg-gray-200 py-10">
{logged ? <div className="flex flex-wrap min-h-screen w-full content-center justify-center bg-gray-200 py-10">
<div className="flex shadow-md">
<div className="flex flex-wrap content-center justify-center rounded-l-md bg-white" style={{ width: "24rem", height: "32rem" }}>
<div className="w-72">
<div className="flex flex-wrap content-center justify-center ">
<h1 className="text-xl font-semibold">url-shortener</h1>
</div>
<small className="text-gray-400 mt-4 flex flex-wrap content-center justify-center ">Welcome {userName}</small>
<small className="text-gray-400 mt-4 flex flex-wrap content-center justify-center ">Short your url!</small>

<form method="post" action="#" className="mt-4">

<form onSubmit={handleShorten} className="mt-4">
<div className="mb-3">
<label className="mb-2 block text-xs font-semibold">Your url </label>
<input type="url" name="url" placeholder="Enter a URL" className="block w-full rounded-md border border-gray-300 focus:border-purple-700 focus:outline-none focus:ring-1 focus:ring-purple-700 py-1 px-1.5 text-gray-500" required/>
<input onChange={(e) => setUrl(e.target.value)} type="url" name="url" placeholder="Enter a URL" className="block w-full rounded-md border border-gray-300 focus:border-purple-700 focus:outline-none focus:ring-1 focus:ring-purple-700 py-1 px-1.5 text-gray-500" required/>
</div>
<div className="mb-3">
<button className="mb-1.5 block w-full text-center text-white bg-purple-700 hover:bg-purple-900 px-2 py-1.5 rounded-md">Make it short!</button>
Expand All @@ -26,6 +103,18 @@ function Page() {
<span className="text-xs text-gray-400 font-semibold"> by </span>
<a href="https://www.github.com/arnavrneo" className="text-xs font-semibold text-purple-700">arnavrneo</a>
</div>
<div className="text-center mt-12">
<div className="flex flex-row justify-center mb-3">
<button onClick={handleLogout} className="mb-1.5 block w-min text-center text-white bg-purple-700 hover:bg-purple-900 px-2 py-1.5 rounded-md">Logout</button>
</div>
</div>

{/*LINK VISIBLE HERE*/}
{visible ?
<div className="text-center">
<span className="text-xs text-gray-400 font-semibold"> by </span>
<a href={shortLink} className="text-xs font-semibold text-purple-700">{shortLink}</a>
</div> : ''}
</div>
</div>

Expand All @@ -35,9 +124,9 @@ function Page() {
<div className="mt-3 w-full">
<p className="text-center">frontend for <span className="text-purple-700">url-shortener </span>(in nextjs)</p>
</div>
</div>
</div> : <FourOOne />}
</div>
)
}

export default Page
export default Main;
41 changes: 0 additions & 41 deletions url-shortener/frontend/app/main/short/page.jsx

This file was deleted.

56 changes: 50 additions & 6 deletions url-shortener/frontend/app/page.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,44 @@
export default function Home() {
"use client"

import React, {useState} from "react";
import {useRouter} from "next/navigation";

export default function Login() {
// form field name depends on these names
const [username, setUsername] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('')
const router = useRouter();

const handleSubmit = async (e) => {
e.preventDefault();

try {
const response = await fetch(process.env.NEXT_PUBLIC_ENDPOINT + '/login', {
method: "POST",
credentials: "include",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
username,
email,
password,
}),
});
console.log(JSON.stringify({
username,
email,
password,
}))
if (response.ok) { // response.ok => for 200 http code; not data.ok
await router.push('/main');
} else {
alert("Invalid credentials");
}
} catch (error) {
console.log(error)
}
};

return (
<div>
<div className="flex flex-wrap min-h-screen w-full content-center justify-center bg-gray-200 py-10">
Expand All @@ -11,15 +51,19 @@ export default function Home() {
<h1 className="text-xl font-semibold">Login</h1>
<small className="text-gray-400">Welcome! Please enter your details</small>

<form method="post" action="#" className="mt-4">
<form onSubmit={handleSubmit} className="mt-4">
<div className="mb-3">
<label className="mb-2 block text-xs font-semibold">Name</label>
<input onChange={(e) => setUsername(e.target.value)} name="username" type="username" placeholder="Your name" className="block w-full rounded-md border border-gray-300 focus:border-purple-700 focus:outline-none focus:ring-1 focus:ring-purple-700 py-1 px-1.5 text-gray-500" required />
</div>
<div className="mb-3">
<label className="mb-2 block text-xs font-semibold">Email</label>
<input type="email" placeholder="Enter your email" className="block w-full rounded-md border border-gray-300 focus:border-purple-700 focus:outline-none focus:ring-1 focus:ring-purple-700 py-1 px-1.5 text-gray-500" />
<input onChange={(e) => setEmail(e.target.value)} type="email" placeholder="Enter your email" className="block w-full rounded-md border border-gray-300 focus:border-purple-700 focus:outline-none focus:ring-1 focus:ring-purple-700 py-1 px-1.5 text-gray-500" required/>
</div>

<div className="mb-3">
<label className="mb-2 block text-xs font-semibold">Password</label>
<input type="password" placeholder="*******" className="block w-full rounded-md border border-gray-300 focus:border-purple-700 focus:outline-none focus:ring-1 focus:ring-purple-700 py-1 px-1.5 text-gray-500" />
<input onChange={(e) => setPassword(e.target.value)} type="password" placeholder="*******" className="block w-full rounded-md border border-gray-300 focus:border-purple-700 focus:outline-none focus:ring-1 focus:ring-purple-700 py-1 px-1.5 text-gray-500" required/>
</div>

{/* FORGOT PASSWORD
Expand All @@ -28,9 +72,9 @@ export default function Home() {
<a href="#" className="text-xs font-semibold text-purple-700">Forgot password?</a>
</div> */}


<div className="mb-3">
<button className="mb-1.5 block w-full text-center text-white bg-purple-700 hover:bg-purple-900 px-2 py-1.5 rounded-md">Sign in</button>
<button type="submit" className="mb-1.5 block w-full text-center text-white bg-purple-700 hover:bg-purple-900 px-2 py-1.5 rounded-md">Sign in</button>
{/* GOOGLE IDP
<button className="flex flex-wrap justify-center w-full border border-gray-300 hover:border-gray-500 px-2 py-1.5 rounded-md">
<img className="w-5 mr-2" src="https://lh3.googleusercontent.com/COxitqgJr1sJnIDe8-jiKhxDx1FrYbtRHKJ9z_hELisAlapwE9LUPh6fcXIfb5vwpbMl4xl9H9TRFPc5NOO8Sb3VSgIBrfRYvW6cUA"/>
Expand Down
55 changes: 47 additions & 8 deletions url-shortener/frontend/app/signup/page.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,41 @@
import React from 'react'
"use client"

import React, {useState} from 'react'
import {useRouter} from "next/navigation";

function Signup() {
const [username, setUsername] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const router = useRouter();

const handleSubmit = async (e) => {
e.preventDefault();

try {
console.log("Signup credentials: ", JSON.stringify({ email, password }))
const response = await fetch(process.env.NEXT_PUBLIC_ENDPOINT + '/register', {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
username,
email,
password,
})
})

if (response.ok) {
await router.push("/");
} else {
alert("Signup error");
}
} catch (error) {
console.log(error)
}
};

function Page() {
return (
<div>
<div className="flex flex-wrap min-h-screen w-full content-center justify-center bg-gray-200 py-10">
Expand All @@ -13,15 +48,19 @@ function Page() {
<h1 className="text-xl font-semibold">Signup</h1>
<small className="text-gray-400">Hey! Get ready for the details</small>

<form className="mt-4">
<form onSubmit={handleSubmit} className="mt-4">
<div className="mb-3">
<label className="mb-2 block text-xs font-semibold">Name</label>
<input onChange={(e) => setUsername(e.target.value)} type="username" placeholder="Your name" className="block w-full rounded-md border border-gray-300 focus:border-purple-700 focus:outline-none focus:ring-1 focus:ring-purple-700 py-1 px-1.5 text-gray-500" required />
</div>
<div className="mb-3">
<label className="mb-2 block text-xs font-semibold">Email</label>
<input type="email" placeholder="Enter your email" className="block w-full rounded-md border border-gray-300 focus:border-purple-700 focus:outline-none focus:ring-1 focus:ring-purple-700 py-1 px-1.5 text-gray-500" />
<input onChange={(e) => setEmail(e.target.value)} type="email" placeholder="Your email" className="block w-full rounded-md border border-gray-300 focus:border-purple-700 focus:outline-none focus:ring-1 focus:ring-purple-700 py-1 px-1.5 text-gray-500" required />
</div>

<div className="mb-3">
<label className="mb-2 block text-xs font-semibold">Password</label>
<input type="password" placeholder="Your super secure password" className="block w-full rounded-md border border-gray-300 focus:border-purple-700 focus:outline-none focus:ring-1 focus:ring-purple-700 py-1 px-1.5 text-gray-500" />
<input onChange={(e) => setPassword(e.target.value)} type="password" placeholder="Your super secure password" className="block w-full rounded-md border border-gray-300 focus:border-purple-700 focus:outline-none focus:ring-1 focus:ring-purple-700 py-1 px-1.5 text-gray-500" required/>
</div>

{/* FORGOT PASSWORD
Expand All @@ -32,7 +71,7 @@ function Page() {


<div className="mb-3">
<button className="mb-1.5 block w-full text-center text-white bg-purple-700 hover:bg-purple-900 px-2 py-1.5 rounded-md">Sign up</button>
<button type="submit" className="mb-1.5 block w-full text-center text-white bg-purple-700 hover:bg-purple-900 px-2 py-1.5 rounded-md">Sign up</button>
{/* GOOGLE IDP
<button className="flex flex-wrap justify-center w-full border border-gray-300 hover:border-gray-500 px-2 py-1.5 rounded-md">
<img className="w-5 mr-2" src="https://lh3.googleusercontent.com/COxitqgJr1sJnIDe8-jiKhxDx1FrYbtRHKJ9z_hELisAlapwE9LUPh6fcXIfb5vwpbMl4xl9H9TRFPc5NOO8Sb3VSgIBrfRYvW6cUA"/>
Expand All @@ -43,7 +82,7 @@ function Page() {

<div className="text-center">
<span className="text-xs text-gray-400 font-semibold"> Done Signup? Login </span>
<a href="/signup" className="text-xs font-semibold text-purple-700">here</a>
<a href="/" className="text-xs font-semibold text-purple-700">here</a>
</div>

</div>
Expand All @@ -60,5 +99,5 @@ function Page() {
)
}

export default Page;
export default Signup;

29 changes: 29 additions & 0 deletions url-shortener/frontend/middleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { NextResponse } from 'next/server'

// TODO: implement this if everything else works out
// This function can be marked `async` if using `await` inside
export async function middleware(request) {

try {
const response = await fetch(process.env.NEXT_PUBLIC_ENDPOINT + "/auth", {
method: "POST",
credentials: "include"
})

console.log(response)
if (response.ok) {
return NextResponse.redirect(request.url)
} else {
return NextResponse.redirect(new URL('/notfound', request.url))
}
} catch (error) {
return NextResponse.redirect(new URL('/notfound', request.url))
}

// return NextResponse.redirect(new URL('/home', request.url))
}

// See "Matching Paths" below to learn more
export const config = {
matcher: '/awdasdsad',
}
Loading

0 comments on commit 75e8cc1

Please sign in to comment.