├── client ├── vercel.json ├── public │ ├── favicon.ico │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── apple-touch-icon.png │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ └── site.webmanifest ├── src │ ├── assets │ │ ├── blogs.png │ │ ├── home.png │ │ ├── logo.jpg │ │ ├── logo.webp │ │ ├── users.png │ │ ├── contact.png │ │ ├── mockup.png │ │ ├── profile.png │ │ ├── recipes.png │ │ ├── signin.png │ │ ├── signup.png │ │ ├── add-blog.png │ │ ├── add-recipe.png │ │ ├── logo_nobg.png │ │ ├── logo_nobg.webp │ │ ├── auth-banner.webp │ │ ├── mockup-nobg.png │ │ ├── single-blog.png │ │ ├── blog-dashboard.png │ │ ├── single-recipe.png │ │ ├── recipes-dashboard.png │ │ ├── index.js │ │ ├── photo.svg │ │ ├── componentLoading.json │ │ └── profile_details.svg │ ├── common │ │ ├── roles.js │ │ ├── dateFormat.js │ │ └── uploadImage.js │ ├── layouts │ │ ├── index.js │ │ ├── RootLayout.jsx │ │ └── DashboardLayout.jsx │ ├── components │ │ ├── noData │ │ │ └── NoData.jsx │ │ ├── scrollToTop │ │ │ └── ScrollToTop.jsx │ │ ├── dashboard │ │ │ ├── Table.jsx │ │ │ └── Sidebar.jsx │ │ ├── loading │ │ │ ├── PageLoading.jsx │ │ │ └── ComponentLoading.jsx │ │ ├── logo │ │ │ └── Logo.jsx │ │ ├── backToTop │ │ │ └── BackToTop.jsx │ │ ├── index.js │ │ ├── hero │ │ │ └── Hero.jsx │ │ ├── homeCategories │ │ │ └── HomeCategories.jsx │ │ ├── shareButton │ │ │ └── ShareButton.jsx │ │ ├── subscribe │ │ │ └── Subscribe.jsx │ │ ├── cards │ │ │ ├── AllCards.jsx │ │ │ ├── SubscribeCard.jsx │ │ │ └── SingleCard.jsx │ │ ├── input │ │ │ └── Input.jsx │ │ ├── button │ │ │ └── Button.jsx │ │ ├── comment │ │ │ └── Comment.jsx │ │ ├── header │ │ │ ├── Header.jsx │ │ │ └── Menu.jsx │ │ ├── footer │ │ │ └── Footer.jsx │ │ └── avatar │ │ │ └── Avatar.jsx │ ├── pages │ │ ├── message │ │ │ ├── Error.jsx │ │ │ ├── CheckoutFailure.jsx │ │ │ ├── CheckoutSuccess.jsx │ │ │ └── Message.jsx │ │ ├── recipe │ │ │ ├── SavedRecipes.jsx │ │ │ ├── MyRecipes.jsx │ │ │ └── Recipe.jsx │ │ ├── home │ │ │ └── Home.jsx │ │ ├── blogs │ │ │ ├── MyBlogs.jsx │ │ │ ├── Blogs.jsx │ │ │ ├── AddBlog.jsx │ │ │ ├── EditBlog.jsx │ │ │ └── SingleBlog.jsx │ │ ├── index.js │ │ ├── dashboard │ │ │ ├── DashboardBlogs.jsx │ │ │ ├── DashboardRecipes.jsx │ │ │ └── Users.jsx │ │ ├── auth │ │ │ ├── SignIn.jsx │ │ │ └── SignUp.jsx │ │ ├── profile │ │ │ └── Profile.jsx │ │ └── contact │ │ │ └── Contact.jsx │ ├── hooks │ │ ├── useTitle.jsx │ │ └── useAuth.jsx │ ├── features │ │ ├── blog │ │ │ ├── blogSlice.js │ │ │ └── blogApiSlice.js │ │ ├── user │ │ │ ├── userSlice.js │ │ │ └── userApiSlice.js │ │ ├── recipe │ │ │ ├── recipeSlice.js │ │ │ └── recipeApiSlice.js │ │ └── auth │ │ │ ├── authSlice.js │ │ │ ├── PersistLogin.jsx │ │ │ ├── RequireAuth.jsx │ │ │ └── authApiSlice.js │ ├── redux │ │ ├── store.js │ │ └── apiSlice.js │ ├── main.jsx │ ├── index.css │ └── App.jsx ├── postcss.config.js ├── .env.example ├── vite.config.js ├── .gitignore ├── README.md ├── .eslintrc.cjs ├── tailwind.config.js ├── package.json └── index.html ├── .gitignore ├── server ├── .env.example ├── config │ ├── rolesList.js │ ├── allowedOrigins.js │ └── corsOptions.js ├── db │ └── conn.js ├── middleware │ ├── errorHandler.js │ ├── credentials.js │ ├── verifyRoles.js │ ├── loginLimit.js │ └── verifyJwt.js ├── routes │ ├── authRoutes.js │ ├── subscriptionRoutes.js │ ├── userRoutes.js │ ├── blogRoutes.js │ └── recipeRoutes.js ├── package.json ├── models │ ├── userModel.js │ ├── blogModel.js │ └── recipeModel.js ├── index.js └── controllers │ ├── subscriptionController.js │ ├── userController.js │ ├── blogController.js │ ├── authController.js │ └── recipeController.js └── LICENSE /client/vercel.json: -------------------------------------------------------------------------------- 1 | { "routes": [{ "src": "/[^.]+", "dest": "/", "status": 200 }] } 2 | -------------------------------------------------------------------------------- /client/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avinash905/Recipen/HEAD/client/public/favicon.ico -------------------------------------------------------------------------------- /client/src/assets/blogs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avinash905/Recipen/HEAD/client/src/assets/blogs.png -------------------------------------------------------------------------------- /client/src/assets/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avinash905/Recipen/HEAD/client/src/assets/home.png -------------------------------------------------------------------------------- /client/src/assets/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avinash905/Recipen/HEAD/client/src/assets/logo.jpg -------------------------------------------------------------------------------- /client/src/assets/logo.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avinash905/Recipen/HEAD/client/src/assets/logo.webp -------------------------------------------------------------------------------- /client/src/assets/users.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avinash905/Recipen/HEAD/client/src/assets/users.png -------------------------------------------------------------------------------- /client/src/assets/contact.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avinash905/Recipen/HEAD/client/src/assets/contact.png -------------------------------------------------------------------------------- /client/src/assets/mockup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avinash905/Recipen/HEAD/client/src/assets/mockup.png -------------------------------------------------------------------------------- /client/src/assets/profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avinash905/Recipen/HEAD/client/src/assets/profile.png -------------------------------------------------------------------------------- /client/src/assets/recipes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avinash905/Recipen/HEAD/client/src/assets/recipes.png -------------------------------------------------------------------------------- /client/src/assets/signin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avinash905/Recipen/HEAD/client/src/assets/signin.png -------------------------------------------------------------------------------- /client/src/assets/signup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avinash905/Recipen/HEAD/client/src/assets/signup.png -------------------------------------------------------------------------------- /client/public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avinash905/Recipen/HEAD/client/public/favicon-16x16.png -------------------------------------------------------------------------------- /client/public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avinash905/Recipen/HEAD/client/public/favicon-32x32.png -------------------------------------------------------------------------------- /client/src/assets/add-blog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avinash905/Recipen/HEAD/client/src/assets/add-blog.png -------------------------------------------------------------------------------- /client/src/assets/add-recipe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avinash905/Recipen/HEAD/client/src/assets/add-recipe.png -------------------------------------------------------------------------------- /client/src/assets/logo_nobg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avinash905/Recipen/HEAD/client/src/assets/logo_nobg.png -------------------------------------------------------------------------------- /client/src/assets/logo_nobg.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avinash905/Recipen/HEAD/client/src/assets/logo_nobg.webp -------------------------------------------------------------------------------- /client/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avinash905/Recipen/HEAD/client/public/apple-touch-icon.png -------------------------------------------------------------------------------- /client/src/assets/auth-banner.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avinash905/Recipen/HEAD/client/src/assets/auth-banner.webp -------------------------------------------------------------------------------- /client/src/assets/mockup-nobg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avinash905/Recipen/HEAD/client/src/assets/mockup-nobg.png -------------------------------------------------------------------------------- /client/src/assets/single-blog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avinash905/Recipen/HEAD/client/src/assets/single-blog.png -------------------------------------------------------------------------------- /client/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /client/src/assets/blog-dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avinash905/Recipen/HEAD/client/src/assets/blog-dashboard.png -------------------------------------------------------------------------------- /client/src/assets/single-recipe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avinash905/Recipen/HEAD/client/src/assets/single-recipe.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.vscode 2 | /client/node_modules 3 | /server/node_modules 4 | /server/.env 5 | /client/.env 6 | /client/src/common/data.js -------------------------------------------------------------------------------- /client/src/assets/recipes-dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avinash905/Recipen/HEAD/client/src/assets/recipes-dashboard.png -------------------------------------------------------------------------------- /client/public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avinash905/Recipen/HEAD/client/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /client/public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avinash905/Recipen/HEAD/client/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /client/src/common/roles.js: -------------------------------------------------------------------------------- 1 | const ROLES = { 2 | Admin: "Admin", 3 | BasicUser: "BasicUser", 4 | ProUser: "ProUser", 5 | }; 6 | 7 | export default ROLES; 8 | -------------------------------------------------------------------------------- /client/src/layouts/index.js: -------------------------------------------------------------------------------- 1 | import RootLayout from "./RootLayout"; 2 | import DashboardLayout from "./DashboardLayout"; 3 | 4 | export { RootLayout, DashboardLayout }; 5 | -------------------------------------------------------------------------------- /server/.env.example: -------------------------------------------------------------------------------- 1 | PORT=5000 2 | CLIENT_BASE_URL=http://localhost:5173 3 | MONGODB_URI= 4 | ACCESS_TOKEN_SECRET= 5 | REFRESH_TOKEN_SECRET= 6 | STRIPE_KEY= 7 | STRIPE_PRICE_ID= -------------------------------------------------------------------------------- /server/config/rolesList.js: -------------------------------------------------------------------------------- 1 | const ROLES_LIST = { 2 | Admin: "Admin", 3 | BasicUser: "BasicUser", 4 | ProUser: "ProUser", 5 | }; 6 | 7 | module.exports = ROLES_LIST; 8 | -------------------------------------------------------------------------------- /server/config/allowedOrigins.js: -------------------------------------------------------------------------------- 1 | const allowedOrigins = [ 2 | "https://recipen.vercel.app", 3 | "https://recipen-backend.onrender.com", 4 | ]; 5 | 6 | module.exports = allowedOrigins; 7 | -------------------------------------------------------------------------------- /client/.env.example: -------------------------------------------------------------------------------- 1 | VITE_BASE_URL=http://localhost:5173 2 | VITE_SERVER_BASE_URL=http://localhost:5000/api 3 | VITE_FORMIK_SECRET= 4 | VITE_CLOUDINARY_PRESET= 5 | VITE_CLOUDINARY_CLOUD_NAME= 6 | VITE_CLOUDINARY_BASE_URL= -------------------------------------------------------------------------------- /client/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react({ 7 | // Add this line 8 | include: "**/*.jsx", 9 | })] 10 | }) -------------------------------------------------------------------------------- /client/public/site.webmanifest: -------------------------------------------------------------------------------- 1 | {"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} -------------------------------------------------------------------------------- /client/src/components/noData/NoData.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const NoData = ({ text }) => { 4 | return ( 5 |
6 | No {text} Found 7 |
8 | ); 9 | }; 10 | 11 | export default NoData; 12 | -------------------------------------------------------------------------------- /client/src/pages/message/Error.jsx: -------------------------------------------------------------------------------- 1 | import { errorAnimation } from "../../assets"; 2 | import Message from "./Message"; 3 | 4 | const Error = () => { 5 | return ( 6 | 10 | ); 11 | }; 12 | 13 | export default Error; 14 | -------------------------------------------------------------------------------- /server/db/conn.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | mongoose.set("strictQuery", false); 3 | 4 | const connectDB = () => { 5 | return mongoose.connect(process.env.MONGODB_URI, { 6 | useUnifiedTopology: true, 7 | useNewUrlParser: true, 8 | }); 9 | }; 10 | 11 | module.exports = connectDB; 12 | -------------------------------------------------------------------------------- /client/src/hooks/useTitle.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | 3 | const useTitle = (title) => { 4 | useEffect(() => { 5 | const prevTitle = document.title; 6 | document.title = title; 7 | 8 | return () => (document.title = prevTitle); 9 | }, [title]); 10 | }; 11 | 12 | export default useTitle; 13 | -------------------------------------------------------------------------------- /client/src/common/dateFormat.js: -------------------------------------------------------------------------------- 1 | const dateFormat = (inputDate) => { 2 | const date = new Date(inputDate); 3 | const options = { year: "numeric", month: "short", day: "numeric" }; 4 | const formattedDate = new Intl.DateTimeFormat("en-US", options).format(date); 5 | return formattedDate; 6 | }; 7 | 8 | export default dateFormat; 9 | -------------------------------------------------------------------------------- /server/middleware/errorHandler.js: -------------------------------------------------------------------------------- 1 | const errorHandler = (err, req, res, next) => { 2 | const errStatus = req.statusCode || 500; 3 | const errMessage = err.message || "Something went wrong"; 4 | return res.status(errStatus).json({ 5 | message: errMessage, 6 | isError: true, 7 | }); 8 | }; 9 | 10 | module.exports = errorHandler; 11 | -------------------------------------------------------------------------------- /client/src/pages/message/CheckoutFailure.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { paymentFailed } from "../../assets"; 3 | import Message from "./Message"; 4 | 5 | const CheckoutFailure = () => { 6 | return ( 7 | 11 | ); 12 | }; 13 | 14 | export default CheckoutFailure; 15 | -------------------------------------------------------------------------------- /server/middleware/credentials.js: -------------------------------------------------------------------------------- 1 | const allowedOrigins = require("../config/allowedOrigins"); 2 | 3 | const credentials = (req, res, next) => { 4 | const origin = req.headers.origin; 5 | if (allowedOrigins.includes(origin)) { 6 | res.header("Access-Control-Allow-Credentials", true); 7 | } 8 | next(); 9 | }; 10 | 11 | module.exports = credentials; 12 | -------------------------------------------------------------------------------- /client/src/components/scrollToTop/ScrollToTop.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | import { useLocation } from "react-router-dom"; 3 | 4 | const ScrollToTop = () => { 5 | const { pathname } = useLocation(); 6 | 7 | useEffect(() => { 8 | window.scrollTo(0, 0); 9 | }, [pathname]); 10 | 11 | return null; 12 | }; 13 | 14 | export default ScrollToTop; 15 | -------------------------------------------------------------------------------- /client/src/pages/message/CheckoutSuccess.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { paymentSuccessful } from "../../assets"; 3 | import Message from "./Message"; 4 | 5 | const CheckoutSuccess = () => { 6 | return ( 7 | 11 | ); 12 | }; 13 | 14 | export default CheckoutSuccess; 15 | -------------------------------------------------------------------------------- /client/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /client/src/layouts/RootLayout.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Outlet } from "react-router-dom"; 3 | import { Header, Footer, BackToTop } from "../components"; 4 | 5 | const RootLayout = () => { 6 | return ( 7 | <> 8 |
9 | 10 | 11 |