added docker file and migrated db to production db
31
api/Dockerfile
Normal file
@ -0,0 +1,31 @@
|
||||
# Creating multi-stage build for production
|
||||
FROM node:20-alpine as build
|
||||
RUN apk update && apk add --no-cache build-base gcc autoconf automake zlib-dev libpng-dev vips-dev git > /dev/null 2>&1
|
||||
ARG NODE_ENV=production
|
||||
ENV NODE_ENV=${NODE_ENV}
|
||||
|
||||
WORKDIR /opt/
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm install -g node-gyp
|
||||
RUN npm config set fetch-retry-maxtimeout 600000 -g && npm install --only=production
|
||||
ENV PATH=/opt/node_modules/.bin:$PATH
|
||||
WORKDIR /opt/app
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
|
||||
# Creating final production image
|
||||
FROM node:20-alpine
|
||||
RUN apk add --no-cache vips-dev
|
||||
ARG NODE_ENV=production
|
||||
ENV NODE_ENV=${NODE_ENV}
|
||||
WORKDIR /opt/
|
||||
COPY --from=build /opt/node_modules ./node_modules
|
||||
WORKDIR /opt/app
|
||||
COPY --from=build /opt/app ./
|
||||
ENV PATH=/opt/node_modules/.bin:$PATH
|
||||
|
||||
RUN chown -R node:node /opt/app
|
||||
USER node
|
||||
EXPOSE 1337
|
||||
CMD ["npm", "run", "start"]
|
||||
BIN
api/bun.lockb
Executable file
@ -6,7 +6,7 @@ export default ({ env }) => {
|
||||
const connections = {
|
||||
mysql: {
|
||||
connection: {
|
||||
host: env('DATABASE_HOST', 'localhost'),
|
||||
host: env('DATABASE_HOST', '192.168.50.107'),
|
||||
port: env.int('DATABASE_PORT', 3306),
|
||||
database: env('DATABASE_NAME', 'strapi'),
|
||||
user: env('DATABASE_USERNAME', 'strapi'),
|
||||
|
||||
|
Before Width: | Height: | Size: 194 KiB |
|
Before Width: | Height: | Size: 571 KiB |
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 2.7 MiB |
|
Before Width: | Height: | Size: 1.8 MiB |
|
Before Width: | Height: | Size: 842 KiB |
|
Before Width: | Height: | Size: 356 KiB |
|
Before Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 682 KiB |
|
Before Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 93 KiB |
|
Before Width: | Height: | Size: 933 KiB |
|
Before Width: | Height: | Size: 7.6 KiB |
@ -1,4 +1,5 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
// https://stackoverflow.com/questions/76164057/next-js-hostname-not-configured-under-images-in-next-config-js-even-though-remot
|
||||
const nextConfig = {
|
||||
async rewrites() {
|
||||
return [
|
||||
@ -12,6 +13,22 @@ const nextConfig = {
|
||||
}
|
||||
]
|
||||
},
|
||||
images: {
|
||||
remotePatterns: [
|
||||
{
|
||||
protocol: "https",
|
||||
hostname: "ih1.redbubble.net",
|
||||
port: "",
|
||||
pathname: "/**",
|
||||
},
|
||||
{
|
||||
protocol: "http",
|
||||
hostname: "localhost",
|
||||
port: "1337",
|
||||
pathname: "/**",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
"use client";
|
||||
import React, {useState} from "react";
|
||||
import React, {useEffect, useState} from "react";
|
||||
import MenuCard from "@/components/ui/MenuCard/MenuCard";
|
||||
import { useParams } from "next/navigation";
|
||||
import Product from "@/../public/batch1/files_list.json";
|
||||
@ -10,26 +10,28 @@ const Products = () => {
|
||||
const catID = useParams();
|
||||
const [maxPrice, setMaxPrice] = useState(100);
|
||||
const [sort, setSort] = useState("asc");
|
||||
const [data, setData] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL +"/products?populate=*", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
Authorization: "Bearer " + process.env.NEXT_PUBLIC_API_TOKEN
|
||||
}
|
||||
});
|
||||
const data = await response.json();
|
||||
// console.log(data.data);
|
||||
// console.log(data.data[0].image.url);
|
||||
setData(data.data);
|
||||
};
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
async function GetData () {
|
||||
// const response = await fetch("/strapi/products?=populate=*", {
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_API_URL +"/products?populate=*", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
Authorization: "Bearer " + process.env.NEXT_PUBLIC_API_TOKEN
|
||||
}
|
||||
});
|
||||
const data = await response.json();
|
||||
// console.log(data.data);
|
||||
// console.log(data.data[0].image.url);
|
||||
return data.data;
|
||||
};
|
||||
const products = GetData();
|
||||
console.log(products);
|
||||
|
||||
return (
|
||||
<div className="products">
|
||||
<div className="left">
|
||||
{/* <div className="left">
|
||||
<div className="filterItem">
|
||||
<h2>Product Categories</h2>
|
||||
<div className="inputItem">
|
||||
@ -70,7 +72,7 @@ const Products = () => {
|
||||
<label htmlFor="desc">Price (Highest first)</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> */}
|
||||
<div className="right">
|
||||
{/* <Image
|
||||
src="/white_logo.png"
|
||||
@ -80,7 +82,7 @@ const Products = () => {
|
||||
alt="Profile picture"
|
||||
/> */}
|
||||
</div>
|
||||
<MenuCard Menu={products} />
|
||||
<MenuCard Menu={data} />
|
||||
{/* <button onClick={GetData} className="bg-blue-500 text-white px-4 py-2 rounded-md">Get Data</button> */}
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -19,44 +19,63 @@ const ProductPage = ({ productId }: any) => {
|
||||
"https://ih1.redbubble.net/image.2997405810.0746/ssrco,slim_fit_t_shirt,womens,101010:01c5ca27c6,front,square_product,600x600.jpg",
|
||||
"https://ih1.redbubble.net/image.2997405810.0746/ssrco,slim_fit_t_shirt,flatlay,101010:01c5ca27c6,front,wide_portrait,750x1000-bg,f8f8f8.jpg",
|
||||
];
|
||||
const [data, setData] = useState([]);
|
||||
const [product, setProduct] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
const request = await fetch(process.env.NEXT_PUBLIC_API_URL +"/products?populate=*", {
|
||||
method: "GET",
|
||||
headers: {
|
||||
Authorization: "Bearer " + process.env.NEXT_PUBLIC_API_TOKEN
|
||||
}
|
||||
});
|
||||
const res = await request.json();
|
||||
// console.log(res.data);
|
||||
console.log(res.data[1].image.url);
|
||||
setData(res.data);
|
||||
setProduct(res.data[parseInt(productId)]?.image?.url);
|
||||
};
|
||||
fetchData();
|
||||
}, [productId]);
|
||||
|
||||
return (
|
||||
<div className="product">
|
||||
<div className="left">
|
||||
<div className="images">
|
||||
<div className="product-image">
|
||||
{/* <Image
|
||||
src={images[parseInt(productId)]}
|
||||
<Image
|
||||
src={`${process.env.NEXT_PUBLIC_UPLOAD_URL+product}`}
|
||||
fill
|
||||
className=""
|
||||
alt="Shirt Mockup"
|
||||
style={{ objectFit: "cover" }}
|
||||
onClick={(e) => setSelectedImage(0)}
|
||||
/> */}
|
||||
<Image
|
||||
/>
|
||||
{/* <Image
|
||||
src={images[0]}
|
||||
fill
|
||||
className=""
|
||||
alt="Shirt Mockup"
|
||||
style={{ objectFit: "cover" }}
|
||||
onClick={(e) => setSelectedImage(0)}
|
||||
/>
|
||||
/> */}
|
||||
</div>
|
||||
<div className="product-image">
|
||||
<Image
|
||||
{/* <Image
|
||||
src={images[1]}
|
||||
fill
|
||||
className=""
|
||||
alt="Shirt Mockup"
|
||||
style={{ objectFit: "cover" }}
|
||||
onClick={(e) => setSelectedImage(1)}
|
||||
/>
|
||||
/> */}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mainImage">
|
||||
<div className="main-image">
|
||||
<Image
|
||||
src={images[selectedImage]}
|
||||
src={data[selectedImage]}
|
||||
fill
|
||||
className=""
|
||||
style={{ objectFit: "cover" }}
|
||||
|
||||
@ -35,7 +35,7 @@ const MenuCard = ({ Menu }: any) => {
|
||||
<div className="w-full h-[75%]">
|
||||
<div className="h-full relative w-full">
|
||||
<Image
|
||||
src={`/${process.env.NEXT_PUBLIC_UPLOAD_URL+menu_item.image.url}`}
|
||||
src={`${process.env.NEXT_PUBLIC_UPLOAD_URL+menu_item?.image?.url}`}
|
||||
alt="product photo"
|
||||
fill
|
||||
style={{ objectFit: "cover", objectPosition: "center" }}
|
||||
|
||||