Skip to content
Open

WMS #36

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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ yarn-debug.log*
yarn-error.log*

# local env files
.env
.env*.local

# vercel
Expand Down
60 changes: 60 additions & 0 deletions app/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@

import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import { authConfig } from "./authconfig";
import { connectToDb } from "./lib/utils";
import { User } from "./lib/models";
import bcrypt from "bcrypt";

const login = async (credentials) =>{

try {
connectToDb()
const user = await User.findOne({username: credentials.username });

if (!user) throw new Error("Wrong credentials!");

const isPasswordCorrect = (credentials.password === user.password)
console.log(isPasswordCorrect)

if (!isPasswordCorrect) throw new Error("Wrong credentials!");

return user;
} catch (error) {

throw new Error("Failed to login!")
}
};

export const { signIn, signOut, auth } = NextAuth({
...authConfig,
providers: [
CredentialsProvider({
async authorize(credentials){
try {
const user = await login(credentials);
return user;
} catch (err) {
console.log(err)
return null;
}
},
}),
],
callbacks:{
async jwt({ token, user }){
if (user) {
token.username = user.username;
token.img = user.img;
}
return token;
},
async session({ session, token }){
if (token) {
session.user.username = token.username;
session.user.img = token.img;
}
return session;
},
},
});
21 changes: 21 additions & 0 deletions app/authconfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@


export const authConfig = {
providers:[],
pages: {
signIn: "/login",
},
callbacks: {
authorized({auth, request}){
const isLoggedIn = auth?.user;
const isOnDashboard = request.nextUrl.pathname.startsWith("/dashboard")
if (isOnDashboard) {
if (isLoggedIn) return true;
return false;
}else if(isLoggedIn) {
return Response.redirect(new URL("/dashboard", request.nextUrl));
}
return true;
},
},
};
24 changes: 24 additions & 0 deletions app/dashboard/layout.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Navbar from "../ui/dashboard/navbar/navbar"
import SideBar from "../ui/dashboard/sidebar/sidebar"
import styles from "../ui/dashboard/dashboard.module.css";
import Footer from "../ui/dashboard/footer/footer";


const Layout = ({children}) => {


return (
<div className={styles.container}>
<div className={styles.menu}>
<SideBar/>
</div>
<div className={styles.content}>
<Navbar/>
{children}
<Footer/>
</div>
</div>
)
}

export default Layout
44 changes: 44 additions & 0 deletions app/dashboard/map/map.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@




.summary{
width: 35%;
display: flex;
flex-direction: column;
justify-content: flex-end;
gap: 10px;
position: absolute;
background-color: rgba(1, 0, 0, 0.637);
text-align: left;
font-size: 10px;
color: #c0b8b8;
font-weight: 600;
right: 0;
padding: 20px;
}

.others ul{
list-style: lower-latin;
list-style-position: inside ;
}

.btn{
display: flexbox;
justify-content: inherit;
background: none;
border: none;
color: #b7ff28;
font-weight: 200;
font-size: 10px;
cursor: pointer;
padding: 8px;
min-width: 10px;
}

.locateBtns{
display: flex;
flex-direction: row;
justify-content: space-between;
gap: 10px;
}
135 changes: 135 additions & 0 deletions app/dashboard/map/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
"use client"

import React, { useEffect, useState } from "react";
import {
APIProvider,
Map,
Marker,
useMapsLibrary,
useMap,
} from "@vis.gl/react-google-maps";
import { darkModeMapStyle } from "@/app/lib/mapStyles";
import styles from "./map.module.css";

export default function Mapper() {
const position = { lat: -17.809456, lng: 31.037992 };
const [a, setA] = useState("-17.820587117773236, 31.02204701024367");
const [b, setB] = useState("-17.820836287961782, 31.046514506847107");

const handleSetA = (value) => {
setA(value);
};

const handleSetB = (value) => {
setB(value);
};

// Define marker positions
const markerPositions = [
{ lat: -17.820587117773236, lng: 31.02204701024367 }, // A
{ lat: -17.820836287961782, lng: 31.046514506847107 }, // B
{ lat: -17.809456, lng: 31.037992 }, // C
];

return (
<div>
<div style={{ height: "90vh", width: "100%" }}>
<APIProvider apiKey="AIzaSyDBSfE6Xg5BY5jSf3_gzr1V52irZGWGGos">
<Map
center={position}
zoom={14}
styles={darkModeMapStyle}
fullscreenControl={false}
zoomControl={true}
>
<Directions a={a} b={b}/>
{markerPositions.map((position, index) => (
<Marker
key={index}
position={position}
/>
))}
</Map>
</APIProvider>
</div>
<div className={styles.locateBtns}>
<button onClick={() => handleSetA("-17.820587117773236, 31.02204701024367")}>
A-B
</button>
<button onClick={() =>
handleSetA("-17.810836287961782, 31.046514506847107")
}>
B-C
</button>
<button onClick={() => handleSetA("-17.809456, 31.037992")}>C-D</button>
</div>
</div>
);
}

function Directions({a, b}) {
const map = useMap();
const routeslibrary = useMapsLibrary("routes");
const [directionsService, setDirectionsService] = useState(null);
const [directionsRenderer, setDirectionsRenderer] = useState(null);
const [routes, setRoutes] = useState([]);
const [routeIndex, setRouteIndex] = useState(0);
const selected = routes[routeIndex];
const leg = selected?.legs[0];

useEffect(() => {
if (!routeslibrary || !map) return;
setDirectionsService(new routeslibrary.DirectionsService());
setDirectionsRenderer(new routeslibrary.DirectionsRenderer({ map }));
}, [routeslibrary, map]);

useEffect(() => {
if (!directionsRenderer || !directionsService) return;

directionsService.route(
{
origin: a,
destination: b,
travelMode: google.maps.TravelMode.DRIVING,
provideRouteAlternatives: true,
},
(response: { routes: React.SetStateAction<any[]>; }) => {
setRoutes(response.routes);
directionsRenderer.setDirections(response);
}
);
}, [a, b, directionsService, directionsRenderer]);

useEffect(() => {
if (!directionsRenderer) return;
directionsRenderer.setRouteIndex(routeIndex);
}, [routeIndex, directionsRenderer]);

if (!leg) return null;

return (
<div className={styles.summary}>
<h2>{selected.summary}</h2>
<p>
{leg.start_address.split(",")[0]} to {leg.end_address.split(",")[0]}
</p>
<p>Distance: {leg.distance?.text}</p>
<p>Duration: {leg.duration?.text}</p>
<h2 className={styles.others}>
Other routes
<ul>
{routes.map((route, index) => (
<li key={route.summary}>
<button
className={styles.btn}
onClick={() => setRouteIndex(index)}
>
{route.summary}
</button>
</li>
))}
</ul>
</h2>
</div>
);
}
28 changes: 28 additions & 0 deletions app/dashboard/page.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import Card from "../ui/dashboard/card/card"
import Chart from "../ui/dashboard/charttest/chart"
import styles from "../ui/dashboard/dashboard.module.css"
import Rightbar from "../ui/dashboard/rightbar/rightbar"
import Transactions from "../ui/dashboard/transactions/transactions"


const Dashboard = () => {

return (
<div className={styles.wrapper}>
<div className={styles.main}>
<div className={styles.cards}>
<Card />
<Card />
<Card />
</div>
<Transactions />
<Chart />
</div>
<div className={styles.side}>
<Rightbar />
</div>
</div>
)
}

export default Dashboard
46 changes: 46 additions & 0 deletions app/dashboard/products/[id]/page.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@

import { updateProduct } from "@/app/lib/actions";
import { fetchProduct } from "@/app/lib/data";
import styles from "@/app/ui/dashboard/products/singleProduct/singleProduct.module.css"
import Image from "next/image"

const SingleProductPage = async ({params}) => {
const {id} = params
const product = await fetchProduct(id)

return(
<div className={styles.container}>
<div className={styles.infoContainer}>
<div className={styles.imgContainer}>
<Image src={product.img || "/noproduct.jpg"} alt="" fill />
</div>
{product.title}
</div>
<div className={styles.formContainer}>
<form action={updateProduct} className={styles.form}>
<input type="hidden" name="id" value={product.id} />
<label>Title</label>
<input type="text" name ="title" placeholder={product.title}/><br/>
<label>Price</label>
<input type="number" name ="price" placeholder={product.price}/>
<label>Stock</label>
<input type="number" name ="stock" placeholder={product.stock}/>
<label>Color</label>
<input type="text" name ="color" placeholder={product.color}/>
<label>Size</label>
<input type="number" name ="size" placeholder={product.size}/>
<label>Cat</label>
<select name="cat" id="cat">
<option value="residential">Residential</option>
<option value="industrial">Industrial</option>
</select>
<label>Description</label>
<textarea type="text" name ="desc" rows= "10" placeholder="Description"/>
<button>Update</button>
</form>
</div>
</div>
);
};

export default SingleProductPage;
Loading