Skip to content

Ft backend #141

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added .dockerfile
Empty file.
4 changes: 3 additions & 1 deletion .env.local
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@
# NextJS environment variable setup: https://nextjs.org/docs/app/building-your-application/configuring/environment-variables

# NEXT_PUBLIC_VAR="sample-value"
# PRIVATE_VAR="sample-value"
# PRIVATE_VAR="sample-value"

MONGO_URI="mongodb://localhost:27017/next-product-site"
47 changes: 47 additions & 0 deletions app/api/login/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { NextRequest, NextResponse } from 'next/server';
import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';
import { connectToDatabase } from '@/infra/db/mongo/mongo';
import User from '@/infra/db/mongo/models/User';

const JWT_SECRET = process.env.JWT_SECRET || 'simple-jwt-secret';

export async function POST(req: NextRequest) {
try {
const { email, password } = await req.json();

if (!email || !password) {
return NextResponse.json({ message: 'Email and password are required' }, { status: 400 });
}

await connectToDatabase();

const existingUser = await User.findOne({ email });

if (!existingUser) {
return NextResponse.json({ message: 'Invalid email or password' }, { status: 400 });
}

const isPasswordMatch = await bcrypt.compare(password, existingUser.password);

if (!isPasswordMatch) {
return NextResponse.json({ message: 'Invalid email or password' }, { status: 400 });
}

const token = jwt.sign({ id: existingUser._id, email: existingUser.email }, JWT_SECRET, { expiresIn: '1h' });

return NextResponse.json(
{
token,
user: {
firstname: existingUser.firstname,
lastname: existingUser.lastname,
email: existingUser.email,
},
},
{ status: 200 }
);
} catch (error) {
return NextResponse.json({ message: 'Internal Server Error', error: error }, { status: 500 });
}
}
32 changes: 32 additions & 0 deletions app/api/product/[id]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import path from 'path';
import fs from 'fs';
import { NextRequest, NextResponse } from 'next/server';
import { Product } from '@/src/type/products';

type IProduct = Omit<Product, 'id'> & {
id: string;
};

export async function GET(req: NextRequest) {
try {
const segments = req.nextUrl.pathname.split('/');
const id = segments[segments.length - 1];

if (!id) {
return NextResponse.json({ message: 'ID is required' }, { status: 400 });
}

const filePath = path.resolve('src/mock/small', 'products.json');
const fileData = fs.readFileSync(filePath, 'utf-8');
const products: IProduct[] = JSON.parse(fileData);

const product = products.find((product) => product.id === id);

if (!product) {
return NextResponse.json({ message: 'Product not found' }, { status: 404 });
}
return NextResponse.json(product, { status: 200 });
} catch (error) {
return NextResponse.json({ message: 'Something went wrong...', error: error }, { status: 500 });
}
}
18 changes: 18 additions & 0 deletions app/api/product/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import fs from 'fs';
import path from 'path';
import { NextResponse } from 'next/server';
import { Product } from '@/src/type/products';

export function GET() {
try {
const filePath = path.resolve('src/mock/small', 'products.json');
const fileData = fs.readFileSync(filePath, 'utf-8');
const products: Product[] = JSON.parse(fileData);

const inStockProducts = products.filter((product) => product.countInStock > 0);

return NextResponse.json(inStockProducts, { status: 200 });
} catch (error) {
return NextResponse.json({ message: 'Something went wrong...', error: error }, { status: 500 });
}
}
28 changes: 28 additions & 0 deletions app/api/product/search/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import fs from 'fs';
import path from 'path';
import { NextRequest, NextResponse } from 'next/server';
import { Product } from '@/src/type/products';

export async function GET(req: NextRequest) {
try {
const searchTerm = req.nextUrl.searchParams.get('q');
if (!searchTerm) {
return NextResponse.json({ message: 'Search term is required' }, { status: 400 });
}

const filePath = path.resolve('src/mock/small', 'products.json');
const fileData = fs.readFileSync(filePath, 'utf-8');
const products: Product[] = JSON.parse(fileData);
const filteredProducts = products.filter((product) =>
product.name.toLowerCase().startsWith(searchTerm.toLowerCase())
);

if (filteredProducts.length === 0) {
return NextResponse.json({ message: 'No product found' }, { status: 404 });
}

return NextResponse.json(filteredProducts, { status: 200 });
} catch (error) {
return NextResponse.json({ message: 'Something went wrong...', error: error }, { status: 500 });
}
}
52 changes: 52 additions & 0 deletions app/api/signup/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { NextRequest, NextResponse } from 'next/server';
import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';
import { connectToDatabase } from '@/infra/db/mongo/mongo';
import User from '@/infra/db/mongo/models/User';

const JWT_SECRET = process.env.JWT_SECRET || 'simple-jwt-secret';

export async function POST(req: NextRequest) {
try {
const { firstname, lastname, email, password } = await req.json();

if (!firstname || !lastname || !email || !password) {
return NextResponse.json({ message: 'All fields are required' }, { status: 400 });
}

await connectToDatabase();
console.log('connected to database');

const existingUser = await User.findOne({ email });

if (existingUser) {
return NextResponse.json({ message: 'Email is already registered' }, { status: 400 });
}

console.log('password', password);

const hashedPassword = await bcrypt.hash(password, 10);
console.log('hashedPassword', hashedPassword);

console.log('newUser 0', User);

const newUser = new User({
firstname,
lastname,
email,
password: hashedPassword,
});

console.log('newUser 1', newUser);
await newUser.save();

console.log('newUser 2', newUser);

const token = jwt.sign({ id: newUser._id, email: newUser.email }, JWT_SECRET, { expiresIn: '1h' });
console.log('token', token);

return NextResponse.json({ token, user: { firstname, lastname, email } }, { status: 201 });
} catch (error) {
return NextResponse.json({ message: 'Internal Server Error', error: error }, { status: 500 });
}
}
30 changes: 30 additions & 0 deletions app/api/user/[id]/orders/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import path from 'path';
import fs from 'fs';
import { Order } from '@/src/type/orders';
import { NextRequest, NextResponse } from 'next/server';

export function GET(req: NextRequest) {
try {
const segments = req.nextUrl.pathname.split('/');
const id = segments[segments.length - 2];

if (!id) {
return NextResponse.json({ message: 'ID is required' }, { status: 400 });
}

const filePath = path.resolve('src/mock/small', 'orders.json');
const fileData = fs.readFileSync(filePath, 'utf-8');

const orders: Order[] = JSON.parse(fileData);

const userOrders = orders.filter((order) => order.user === id);

if (userOrders.length) {
return NextResponse.json(userOrders, { status: 200 });
} else {
return NextResponse.json({ message: 'Orders not found' }, { status: 404 });
}
} catch (error) {
return NextResponse.json({ message: 'Something went wrong...', error: error }, { status: 500 });
}
}
29 changes: 29 additions & 0 deletions app/api/user/[id]/orders/total/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { NextRequest, NextResponse } from 'next/server';
import path from 'path';
import fs from 'fs';
import { Order } from '@/src/type/orders';

export async function GET(req: NextRequest) {
try {
const segments = req.nextUrl.pathname.split('/');
const id = segments[segments.length - 3];

if (!id) {
return NextResponse.json({ message: 'ID is required' }, { status: 400 });
}

const filePath = path.resolve('src/mock/small', 'orders.json');
const fileData = fs.readFileSync(filePath, 'utf-8');
const orders: Order[] = JSON.parse(fileData);

const userOrders = orders.filter((order) => order.user === id);
if (userOrders.length === 0) {
return NextResponse.json({ total: 0 });
}
const totalSum = userOrders.reduce((sum, order) => sum + (order.total || 0), 0);

return NextResponse.json({ total: totalSum });
} catch (error) {
return NextResponse.json({ message: 'Something went wrong...', error: error }, { status: 500 });
}
}
33 changes: 33 additions & 0 deletions app/api/user/[id]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import fs from 'fs';
import path from 'path';
import { User } from '@/src/type/users';
import { NextRequest, NextResponse } from 'next/server';

type IUser = Omit<User, 'id'> & {
id: string;
};

export async function GET(req: NextRequest) {
try {
const segments = req.nextUrl.pathname.split('/');
const id = segments[segments.length - 1];

if (!id) {
return NextResponse.json({ message: 'ID is required' }, { status: 400 });
}

const filePath = path.resolve('src/mock/small', 'users.json');
const fileData = fs.readFileSync(filePath, 'utf-8');
const users: IUser[] = JSON.parse(fileData);

const user = users.find((user) => user.id === id);

if (user) {
return NextResponse.json(user, { status: 200 });
} else {
return NextResponse.json({ message: 'User not found' }, { status: 404 });
}
} catch (error) {
return NextResponse.json({ message: 'Something went wrong...', error: error }, { status: 500 });
}
}
3 changes: 0 additions & 3 deletions docs/backend/index.md

This file was deleted.

Loading