-
المساهمات
604 -
تاريخ الانضمام
-
تاريخ آخر زيارة
نوع المحتوى
ريادة الأعمال
البرمجة
التصميم
DevOps
التسويق والمبيعات
العمل الحر
البرامج والتطبيقات
آخر التحديثات
قصص نجاح
أسئلة وأجوبة
كتب
دورات
كل منشورات العضو محمود سعداوي2
-
السلام عليكم. بعد إتمام تحميل وتنصيب posteqres أردت فتح الوجهة الرسومية لقاعدة البيانات postegrs واجهت هذا المشكل شكرا على المساعدة
- 4 اجابة
-
- 1
-
السلام عليكم. هل يمكنني إنشاء إمتداد جوجل google chrome extension بلغة الجافاسكريبت react | node | next وكيف ذلك. شكرا.
- 2 اجابة
-
- 2
-
السلام عليكم. أرجو توضيح سبب طباعة النتيجة في الدالتين التالييتين 1. const sayHello = () => { return "Hello" } console.log(sayHello.prototype) /* النتيجة undefined */ 2. function sayHello() { return "Hello" } console.log(sayHello.prototype) /** النتيجة: constructor : ƒ sayHello() [[Prototype]] : Object */ أو بطرقة أخرى لماذا تمت طباعة undefined في الدالة السهمية شكرا
- 2 اجابة
-
- 1
-
السلام عليكم. هل تعلم typescript يتطلب وجوبا تعلم oop. شكرا.
- 2 اجابة
-
- 1
-
مارأيك بطريقة كتابة الكود. هل تخضع لbest practice
- 4 اجابة
-
- 1
-
السلام عليكم. أرجو مساعدتي في التحقق من البيانات بواسطة cookie و jwt في مشروع Nextjs 14. تظهر لي رسالة الخطأ التالية { "message": "Not authorized, no token" } للتوضيح: في البداية قمت بتوليد token و cookie utils/generateToken import jwt from 'jsonwebtoken' const generateToken = (id) => { const token = jwt.sign({ userId: id }, process.env.JWT_SECRET, { expiresIn: '1d' }); return token; } const setTokenCookie = (response, token) => { response.cookies.set('token', token, { httpOnly: true, secure: process.env.NODE_ENV !== 'development', sameSite: 'strict', maxAge: 60*60*24 }); } export { generateToken, setTokenCookie }; ثم قمت بإنشاء الحساب وتسجيل الدخول (سوف أعرض تسجيل الدخول لأنهما مشابهين كثيرا) app/api/auth/login/route.js import connectDB from "@/config/connectDB"; import User from "@/models/User"; import { generateToken, setTokenCookie } from "@/utils/generateToken"; import bcrypt from "bcryptjs"; import { NextResponse } from "next/server"; /** * Method: POST * route : /api/auth/login */ export const POST = async (request) => { await connectDB(); try { const { email, password } = await request.json(); const user = await User.findOne({ email }); const isMatch = await bcrypt.compare(password, user.password) if (!user || !isMatch) { return new NextResponse("Invalid Credentials", { status: 400 }) } if (user) { const token = generateToken(user._id); const response = new NextResponse( JSON.stringify({ user: user.email }), { status: 200 } ); setTokenCookie(response, token); return response; } else { return new NextResponse("Failed to create user", { status: 500 }); } } catch (error) { console.log(error); return new Response("Something went wrong => Register User", { status: 500, }); } }; ثم قمت بتحديد الوسائط middlewares/protect.js import User from "@/models/User"; import { cookies } from "next/headers"; const protect = async (request) => { const cookieStore = cookies() const token = cookieStore.get('jwt')?.value; if (!token) { throw new Error('Not authorized, no token'); } try { const decoded = jwt.verify(token, process.env.JWT_SECRET); const user = await User.findById(decoded.userId) if (!user) { throw new Error('Not authorized, user not found'); } return user; } catch (error) { console.error(error); throw new Error('Not authorized, token failed'); } }; export default protect; في النهاية لتجربة التحقق قمت ب: app/api/auth/me/route.js import connectDB from "@/config/connectDB" import protect from "@/middleware/protect" import User from "@/models/User" import { NextResponse } from "next/server" /** * Test If Route Is Protected */ export const GET = async (request) => { await connectDB() try { const user = await protect(request) const me = await User.findById(user._id ) return NextResponse.json(me, { status: 200 }) } catch (error) { return NextResponse.json({ message: error.message }, { status: 401 }); } } الرجاء مساعدتي في تحديد سبب فشل التحقق من البيانات. شكرا.
- 4 اجابة
-
- 4
-
السلام عليكم. كمبرمج مبتدئ، هل ينصح باستخدام مكتبة Nextjs عند الحماية والتحقق NextAuth . أم الأجدر أن يقوم المبرمج بنفسه بالحماية والتحقق دون اللجوء لمثل هذه المكتبات في إطار التمرس أكثر. شكرا
- 3 اجابة
-
- 2
-
مرحبا مجددا @Mustafa Suleiman المشكل أني أستعمل nextjs 14 حيث أستخدم useEffect لجلب البيانات. هل تيعين علي تغيير الكود. كمثال: const pageSearchResultsPage = () => { const [properties, setProperties] = useState([]); const [loading, setLoading] = useState(true); const searchParams = useSearchParams(); const location = searchParams.get("location"); const propertyType = searchParams.get("propertyType"); useEffect(() => { const fetchSearchResults = async () => { try { const res = await fetch( `/api/properties/search?location=${location}&propertyType=${propertyType}` ); if (res.status === 200) { const data = await res.json(); console.log('data') setProperties(data); } else { setProperties([]); } } catch (error) { console.log(error); toast.error("Fetching search properties is failed!"); } finally { setLoading(false); } }; fetchSearchResults(); }, [location, propertyType]); return ( <> <section className="bg-green-700 py-4"> <div className="max-w-7xl mx-auto px-4 flex flex-col items-start sm:px-6 lg:px-8"> <PropertySearchForm /> </div> </section> {loading ? ( <Spinner loading={loading} /> ) : ( <section className="px-4 py-6"> <div className="container-xl lg:container m-auto px-4 py-6"> <Link href="/properties" className="flex items-center text-green-500 hover:underline mb-3" > <FaArrowAltCircleLeft className="mr-2 mb-1" /> Back To Properties </Link> <h1 className="text-2xl mb-4">Search Results</h1> {properties.length === 0 ? ( <p>No search results found</p> ) : ( <div className="grid grid-cols-1 md:grid-cols-3 gap-6"> {properties.map((property) => ( <PropertyCard key={property._id} property={property} /> ))} </div> )} </div> </section> )} </> ); }; شكرا
-
السلام عليكم. عند رفع المشروع على vercel، ظهرت الأخطاء التالية: q [Error]: Dynamic server usage: Route /api/properties/search couldn't be rendered statically because it used `request.url`. See more info here: https://nextjs.org/docs/messages/dynamic-server-error at W (/vercel/path0/node_modules/next/dist/compiled/next-server/app-route.runtime.prod.js:6:21106) at Object.get (/vercel/path0/node_modules/next/dist/compiled/next-server/app-route.runtime.prod.js:6:28459) at c (/vercel/path0/.next/server/app/api/properties/search/route.js:1:607) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async /vercel/path0/node_modules/next/dist/compiled/next-server/app-route.runtime.prod.js:6:36258 description: "Route /api/properties/search couldn't be rendered statically because it used `request.url`. See more info here: https://nextjs.org/docs/messages/dynamic-server-error", digest: 'DYNAMIC_SERVER_USAGE' للتوضيح: هذه بعض المكونات التي أشير لي بأنها تحتوي أخطاء علما وأن المشروع يعمل بصفة عادية على المتصفح api/properties import cloudinary from "@/config/cloudinary"; import connectDB from "@/config/database"; import Property from "@/models/Property"; import { getSessionUser } from "@/utils/getSessionUser"; /** * method: GET * route : /api/properties */ export const GET = async (request) => { try { await connectDB(); const page = request.nextUrl.searchParams.get("page") || 1; const pageSize = request.nextUrl.searchParams.get("pageSize") || 5; const skip = (page - 1) * pageSize; const total = await Property.countDocuments({}); const properties = await Property.find({}).skip(skip).limit(pageSize); const result = { total, properties, }; return new Response(JSON.stringify(result), { status: 200 }); } catch (error) { console.log(error); return new Response("Something went wrong", { status: 500 }); } }; /** * method: POST * route : api/properties/add */ export const POST = async (request) => { try { await connectDB(); const sessionUser = await getSessionUser(); if (!sessionUser || !sessionUser.userId) { return new Response("UserId is required", { status: 401, }); } const { userId } = sessionUser; const formData = await request.formData(); const amenities = formData.getAll("amenities"); const images = formData.getAll("images").filter((img) => img.name !== ""); const propertyData = { type: formData.get("type"), name: formData.get("name"), description: formData.get("description"), location: { street: formData.get("location.street"), city: formData.get("location.city"), state: formData.get("location.state"), zipcode: formData.get("location.zipcode"), }, beds: formData.get("beds"), baths: formData.get("baths"), square_feet: formData.get("square_feet"), amenities, rates: { weekly: formData.get("rates.weekly"), monthly: formData.get("rates.monthly"), nightly: formData.get("rates.nightly"), }, seller_info: { name: formData.get("seller_info.name"), email: formData.get("seller_info.email"), phone: formData.get("seller_info.phone"), }, owner: userId, }; // Upload Images To Cloudinary const imageUploadPromises = []; for (const image of images) { const imageBuffer = await image.arrayBuffer(); const imageArray = Array.from(new Uint8Array(imageBuffer)); const imageData = Buffer.from(imageArray); // Convert The Image Data To Base64 const imageBase64 = imageData.toString("base64"); // Make request to upload to cloudinary const result = await cloudinary.uploader.upload( `data:image/png;base64,${imageBase64}`, { folder: "propertypulse", secure: true, rejectUnauthorized: false, } ); imageUploadPromises.push(result.secure_url); // Wait for all images to upload const uploadedImages = await Promise.all(imageUploadPromises); // Add Uploaded images to propertyData object propertyData.images = uploadedImages; } const newProperty = new Property(propertyData); await newProperty.save(); return Response.redirect( `${process.env.NEXTAUTH_URL}/properties/${newProperty._id}` ); // return new Response(JSON.stringify({message: 'success'}), { status: 200 }) } catch (error) { console.error("This is the error we are looking for: ", error); return new Response("Failed to add property", { status: 500 }); } }; /api/properties/search import connectDB from "@/config/database"; import Property from "@/models/Property"; /** * method: GET * route : /api/properties/search */ export const GET = async (request) => { try { await connectDB(); const { searchParams } = new URL(request.url); const location = searchParams.get("location"); const propertyType = searchParams.get("propertyType"); const locationPattern = new RegExp(location, "i"); // Match location pattern against database fields let query = { $or: [ { name: locationPattern }, { description: locationPattern }, { "location.street": locationPattern }, { "location.city": locationPattern }, { "location.state": locationPattern }, { "location.zipcode": locationPattern }, ], }; // Only check for property if its not 'All' if (propertyType && propertyType !== 'All') { const typePattern = new RegExp(propertyType, "i"); query.type = typePattern } const properties = await Property.find(query) return new Response(JSON.stringify(properties), { status: 200 }); } catch (error) { console.log(error); return new Response("Something went wrong => Search Properties", { status: 500, }); } }; package.json { "name": "next_app", "version": "0.1.0", "private": true, "scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint" }, "dependencies": { "@maptiler/leaflet-maptilersdk": "^2.0.0", "cloudinary": "^2.2.0", "leaflet": "^1.9.4", "leaflet-control-geocoder": "^2.4.0", "leaflet-defaulticon-compatibility": "^0.1.2", "mongodb": "^6.8.0", "mongoose": "^8.4.4", "next": "14.2.4", "next-auth": "^4.24.7", "opencage-api-client": "^1.0.7", "react": "^18", "react-dom": "^18", "react-icons": "^5.2.1", "react-leaflet": "^4.2.1", "react-photoswipe-gallery": "^1.3.9", "react-share": "^5.1.0", "react-spinners": "^0.14.1", "react-toastify": "^10.0.5" }, "devDependencies": { "postcss": "^8", "tailwindcss": "^3.4.1" } } شكرا لكم.
- 3 اجابة
-
- 2
-
السلام عليكم. أود تعلم قواعد البيانات العلائقية. أريد أن تنصحوني أيا أختار mysql postegress sequilize مع العلم أني مبرمج ويب بالتقنيات التالية react node express nextjs شكرا
- 2 اجابة
-
- 2
-
السلام عليكم. في الآونة الأخيرة كثر تداول مصطلح البرمجيات كخدمة. لدي بعض الأسئلة حول هذا الموضوع: هل هذه الخدمة تعني تطوير تطبيق كامل يبدأ بالتصميم ثم التطوير والبرمجة فالرفع وحجز الاستضافة. ماهي لغات البرمجة التي تقتضيها هي الخدمة أو على الأرجح أكثر اللغات شيوعا لهذه للخدمة. أمثلة عملية لمثل هذه الخدمات. شكرا.
- 3 اجابة
-
- 1
-
السلام عليكم. في الكود التالي: "use client" import React, { useEffect, useState } from "react"; import Link from "next/link"; import { useParams } from "next/navigation"; import { FaArrowLeft } from 'react-icons/fa'; import { fetchProperty } from "@/utils/requests"; const PropertyPage = () => { const [property, setProperty] = useState(null) const [loading, setLoading] = useState(true) const { id } = useParams() console.log(id) useEffect(() => { const fetchPropertyData = async() => { if (!id) return try { const property = await fetchProperty(id) setProperty(property) } catch (error) { console.error('Error fetching property: ', error) } finally { setLoading(false) } if (property === null) { fetchPropertyData() } } }, [id, property]) console.log(property) if (loading) return <h1>Loading...</h1> if (!property) return <h1> No Property Found </h1> return ( <> <section> <div className="container m-auto py-6 px-6"> <Link href="/properties" className="text-green-500 hover:text-green-600 flex items-center" > <FaArrowLeft className="mr-2" /> Back to Properties </Link> </div> </section> <section className="bg-green-50"> <div className="container m-auto py-10 px-6"> <div className="grid grid-cols-1 md:grid-cols-70/30 w-full gap-6"> <aside className="space-y-4"> property single page </aside> </div> </div> </section> </> ); }; export default PropertyPage; تظهر على شاشة المستخدم Loading... والسبب هو أن قيمة loading: false. للتوضيح: route.js export const GET = async (request, { params }) => { try { await connectDB(); const property = await Property.findById(params.id); if (!property) return new Response("Property Not Found", { status: 404 }); return new Response(JSON.stringify(property), { status: 200 }); } catch (error) { console.log(error); return new Response("Something went wrong", { status: 500 }); } }; requests.js const apiDomain = process.env.NEXT_PUBLIC_API_DOMAIN || null; async function fetchProperty(id) { try { if (!apiDomain) { return null; } const res = await fetch(`${apiDomain}/properties/${id}`); if (!res.ok) { throw new Error("Failed to fetch data"); } return res.json(); } catch (error) { console.log(error); return null; } } أعتقد أن المشكل هو في عدم التعرف على NEXT_PUBLIC_API_DOMAIN شكرا على مساعدتي في تجاوز هذا الخطأ
- 1 جواب
-
- 2
-
السلام عليكم. Warning: A component was suspended by an uncached promise. Creating promises inside a Client Component or hook is not yet supported, except via a Suspense-compatible library or framework. at PropertyPage أرجو التوضيح: في الكود الآتي: "use client" import React, { useEffect, useState } from "react"; import Link from "next/link"; import { useParams } from "next/navigation"; import { FaArrowLeft } from 'react-icons/fa'; import { fetchProperty } from "@/utils/requests"; const PropertyPage = async() => { const [property, setProperty] = useState(null) const [loading, setLoading] = useState(true) const { id } = useParams() useEffect(() => { const fetchPropertyData = async() => { if (!id) return try { const property = await fetchProperty(id) setProperty(property) } catch (error) { console.error('Error fetching property', error) } finally { setLoading(false) } if (property === null) { fetchPropertyData() } } }, [id, property]) return ( <> <section> <div className="container m-auto py-6 px-6"> <Link href="/properties" className="text-green-500 hover:text-green-600 flex items-center" > <FaArrowLeft className="mr-2" /> Back to Properties </Link> </div> </section> <section className="bg-green-50"> <div className="container m-auto py-10 px-6"> <div className="grid grid-cols-1 md:grid-cols-70/30 w-full gap-6"> <aside className="space-y-4"> property single page </aside> </div> </div> </section> </> ); }; export default PropertyPage; ظهرت رسالة الخطأ المذكورة ولكن عند حذف async في الدالة PropertyPage صار الكود يعمل بدون مشكل. سؤالي هو لماذا async فعلت الخطأ. شكرا للتوضيح.
- 2 اجابة
-
- 3
-
شكرا. بصراحة في بعض الأحيان لا أفهم شيئا. في الصباح طرحت السؤال والكود لايعمل. الآن صار الكود يشتغل دون أن أقوم بأي تغيير
- 3 اجابة
-
- 1
-
السلام عليكم. الرجاء مساعدتي في جلب البيانات من الخادم. route.js /** * method: GET * path : api/properties */ export const GET = async( request ) => { try { await connectDB() const properties = await Property.find({}) return new Response(JSON.stringify(properties), { status: 200 }) } catch (error) { console.log(error) return new Response('Something went wrong', { status: 500 }) } } connectDB import mongoose from 'mongoose' let connected = false const connectDB = async () => { mongoose.set('strictQuery', true) // If the database is already connected, don't connect again if (connected) { console.log('Mongo DB is already connected ...') return; } // Connect to MongoDB try { await mongoose.connect(process.env.MONGO_URI); connected = true console.log('MongoDB connected ...') } catch (error) { console.log(error) } } export default connectDB; في هذه الحالة عندما أدخل على الرابط التالي http://localhost:3000/api/properties تظهر لي مصفوفة الproperties propeties/page.jsx import React from "react"; import PropertyCard from '@/components/PropertyCard'; async function fetchProperties() { try { const res = await fetch(`${process.env.NEXT_PUBLIC_API_DOMAIN}/properties`) if (!res.ok) { throw new Error('Failed to fetch data') } return res.json() } catch (error) { console.log(error) } } const PropertiesPage = async () => { const properties = await fetchProperties() console.log(properties) return ( <section className='px-4 py-6'> <div className='container-xl lg:container m-auto px-4 py-6'> {properties.length === 0 ? ( <p>No properties found</p> ) : ( <div className='grid grid-cols-1 md:grid-cols-3 gap-6'> {properties.map((property) => ( <PropertyCard key={property._id} property={property} /> ))} </div> )} </div> </section> ); }; export default PropertiesPage; في هذه الحالة مصفوفة الproperties فارغة وتظهر لي No properties found في طرف العميل شكرا.
- 3 اجابة
-
- 1
-
الحل هو إضافة icon.png في ملف app ثم يقع إدراجها مباشرة الكود import React from 'react' import '@/assets/styles/globals.css' export const metadata = { title: 'Property Pulse', description: 'Find your dream rental property', keywords: 'rental, find rentals, property, find properties', } const MainLayout = ({ children }) => { return ( <html lang='en'> <body> <div>{children}</div> </body> </html> ) } export default MainLayout شكرا
- 5 اجابة
-
- 1
-
للأسف أخي
-
السلام عليكم. أريد إضافة favicon في تطبيق next الكود: layout.jsx import React from 'react' import '@/assets/styles/globals.css' export const metadata = { title: 'Property Pulse', description: 'Find your dream rental property', keywords: 'rental, find rentals, property, find properties', icons: { icon: "/assets/images/ico.png", }, } const MainLayout = ({ children }) => { return ( <html lang='en'> <body> <div>{children}</div> </body> </html> ) } export default MainLayout تموضع ملفات المشروع: شكرا
- 5 اجابة
-
- 1
-
السلام عليكم. أواجه مشكل في جلب البيانات من الخادم حيث لايتسنى إظهار هذه البيانات على الواجهة الأمامية إلا بعد تحديث الصفحة. الكود. إضافة كتاب (الواجهة الخلفية) // method POST // route api/books // desc Create new book // access Private | admin const createBook = asyncHandler(async(req, res) => { try{ // Image Validation if (!req.file) { return res.status(400).json({ message: "no image provided" }); } // Upload Photo const imagePath = path.join(__dirname, `../images/${req.file.filename}`); const result = await cloudinaryUploadImage(imagePath); // Save new post in database const book = await Book.create({ title: req.body.title, description: req.body.description, category: req.body.category, user: req.userId, image: { url: result.secure_url, publicId: result.public_id, }, author: req.body.author, language: req.body.language, PublicationDate: req.body.PublicationDate, }); // Send response to the client res.status(201).json(book); // 6. Remove image from the server fs.unlinkSync(imagePath); } catch (err) { console.log(err.message) res.status(500).send('Server error') } }); إضافة كتاب الواجهة الأمامية // bookSlice getBooks(state, action) { state.books = action.payload; }, setBooks(state, action) { state.books = [...state.books, action.payload] }, // bookApiCall export function addBook(newBook) { return async (dispatch, getState) => { try { dispatch(bookActions.setLoading()) const {data} = await axios.post(`${BOOK_URL}`, newBook, { headers: { "authorization": getState().auth.user.accessToken } }); dispatch(bookActions.setBooks(data)); dispatch(bookActions.clearLoading()); } catch (error) { toast.error(error?.response?.data.message); dispatch(bookActions.clearLoading()); } }; } /** * Add New Book */ const [fileName, setFileName] = useState(null); const [title, setTitle] = useState(""); const [description, setDescription] = useState(""); const [category, setCategory] = useState(""); const [author, setAuthor] = useState(""); const [PublicationDate, setPublicationDate] = useState(""); const [language, setLanguage] = useState(""); const formSubmitHandler = (e) => { e.preventDefault(); if (title.trim() === "") return toast.error("Book Title is required"); if (category.trim() === "") return toast.error("Book Category is required"); if (description.trim() === "") return toast.error("Book Description is required"); if (author.trim() === "") return toast.error("Book Author is required"); if (language.trim() === "") return toast.error("Book Language is required"); if (PublicationDate.trim() === "") return toast.error("Book Publication Date is required"); if (!fileName) return toast.error("Book Image is required"); const formData = new FormData(); formData.append("image", fileName); formData.append("title", title); formData.append("description", description); formData.append("category", category); formData.append("author", author); formData.append("language", language); formData.append("PublicationDate", PublicationDate); dispatch(addBook(formData)) setFileName(null) setTitle("") setDescription("") setCategory("") setAuthor("") setPublicationDate("") setLanguage("") }; /** * Fetch All Books With Pagination */ useEffect(() => { dispatch(fetchBooks()); }, [dispatch]); شكرا على المساعدة.
- 1 جواب
-
- 1
-
السلام عليكم. الرجاء مساعدتي في حل الخطأ التالي react-dom.development.js:86 Warning: validateDOMNesting(...): <a> cannot appear as a descendant of <a>. at a Code: import React, { useState } from "react"; import "./header.css"; import { Link, NavLink } from "react-router-dom"; import { CiMenuBurger } from "react-icons/ci"; import { RiCloseFill } from "react-icons/ri"; import logo from "../../images/logo.png"; import { useSelector } from "react-redux"; import { BsThreeDotsVertical } from "react-icons/bs"; import Dropdown from "./Dropdown"; function Header() { const [click, setClick] = useState(false); const { user } = useSelector((state) => state.auth); const handleClick = () => setClick(!click); return ( <> <nav className="navbar"> <div className="nav-container"> <Link to="/" className="nav-logo"> <div className="logo"> <img src={logo} alt="logo" /> </div> <span className="logo-icon">Bookly</span> </Link> <ul className={click ? "nav-menu active" : "nav-menu"}> {user ? ( <> <li className="nav-item"> <NavLink to="/" className={({ isActive }) => isActive ? "active" : "nav-links" } onClick={handleClick} > Home </NavLink> </li> {user.isAdmin && ( <li className="nav-item"> <NavLink to="/admin" className={({ isActive }) => isActive ? "active" : "nav-links" } onClick={handleClick} > Dashboard </NavLink> </li> )} <li className="nav-item"> <NavLink to="/login" className={({ isActive }) => isActive ? "active" : "nav-links nav-dropdown" } onClick={handleClick} > {user.name} <BsThreeDotsVertical /> <Dropdown /> </NavLink> </li> </> ) : ( <> <li className="nav-item"> <NavLink to="/" className={({ isActive }) => isActive ? "active" : "nav-links" } onClick={handleClick} > Home </NavLink> </li> <li className="nav-item"> <NavLink to="/login" className={({ isActive }) => isActive ? "active" : "nav-links" } onClick={handleClick} > Login </NavLink> </li> </> )} </ul> <div className="nav-icon" onClick={handleClick}> {click ? ( <span className="icon"> <RiCloseFill /> </span> ) : ( <span className="icon"> <CiMenuBurger /> </span> )} </div> </div> </nav> </> ); } export default Header; Child Component import React from 'react' import { useDispatch } from 'react-redux' import { logoutUser } from '../../redux/apiCalls/authApiCalls' import { Link } from 'react-router-dom' function Dropdown() { const dispatch = useDispatch() const logout = () => { dispatch(logoutUser()) } return ( <div className='dropdown'> <ul className="dropdown-menu"> <li className="dropdown-item" onClick={logout}> Logout </li> <li className="dropdown-item"> <Link className='dropdown-item-link' to='/favorites'> My Favorites </Link> </li> </ul> </div> ) } export default Dropdown شكرا.
- 1 جواب
-
- 1
-
السلام عليكم. بعد تقييم منتج محدد أريد إظهار التقييم على الواجهة البرمجية. Slice import { createSlice } from "@reduxjs/toolkit"; const bookSlice = createSlice({ name: "book", initialState: { books: [], reviews: [], error: false, loading: false, }, reducers: { addReviews(state, action) { state.books = action.payload }, getReviews(state, action) { state.reviews = action.payload; }, setLoading(state) { state.loading = true; }, clearLoading(state) { state.loading = false; }, } }) const bookReducer = bookSlice.reducer; const bookActions = bookSlice.actions; export {bookActions, bookReducer} apiCall // Get Book Reviews export function getBookReviews(bookId) { return async (dispatch, getState) => { try { dispatch(bookActions.setLoading()) const {data} = await axios.get(`${BOOK_URL}/${bookId}/reviews`, { headers: { "authorization": getState().auth.user.accessToken } }); dispatch(bookActions.getReviews(data)); dispatch(bookActions.clearLoading()); } catch (error) { toast.error(error?.response?.data.message); dispatch(bookActions.clearLoading()); } }; } // Post Review export function postReview(bookId, review) { return async (dispatch, getState) => { try { dispatch(bookActions.setLoading()) const {data} = await axios.post(`${BOOK_URL}/${bookId}/reviews`, review, { headers: { "authorization": getState().auth.user.accessToken } }); toast.success(data?.message) dispatch(bookActions.addReviews()) dispatch(bookActions.getReviews(review)); dispatch(bookActions.clearLoading()); } catch (error) { toast.error(error?.response?.data.message); dispatch(bookActions.clearLoading()); } }; } React Component // Get Book Reviews export function getBookReviews(bookId) { return async (dispatch, getState) => { try { dispatch(bookActions.setLoading()) const {data} = await axios.get(`${BOOK_URL}/${bookId}/reviews`, { headers: { "authorization": getState().auth.user.accessToken } }); dispatch(bookActions.getReviews(data)); dispatch(bookActions.clearLoading()); } catch (error) { toast.error(error?.response?.data.message); dispatch(bookActions.clearLoading()); } }; } // Post Review export function postReview(bookId, review) { return async (dispatch, getState) => { try { dispatch(bookActions.setLoading()) const {data} = await axios.post(`${BOOK_URL}/${bookId}/reviews`, review, { headers: { "authorization": getState().auth.user.accessToken } }); toast.success(data?.message) dispatch(bookActions.addReviews()) dispatch(bookActions.getReviews(review)); dispatch(bookActions.clearLoading()); } catch (error) { toast.error(error?.response?.data.message); dispatch(bookActions.clearLoading()); } }; } Review.jsx import moment from "moment"; import React from "react"; import Rating from "../rating/Rating"; import { Oval } from "react-loader-spinner"; import { useSelector } from "react-redux"; function Reviews() { const { loading, reviews } = useSelector((state) => state.book); return ( <div className="get-reviews"> <h2 className="get-reviews-title">Reviews ({reviews?.length})</h2> <div className="reviews"> {loading ? ( <Oval height={120} width={120} color="rgb(247, 96, 14)" wrapperStyle={{ height: "90vh", display: "flex", alignItems: "center", justifyContent: "center", }} wrapperClass="" visible={true} ariaLabel="oval-loading" secondaryColor="#E2E2E2" strokeWidth={3} strokeWidthSecondary={3} /> ) : ( Array.isArray(reviews) && reviews.map((el, key) => ( <div className="user-review" key={key}> <p> <span>{el?.username ? el?.username : "Unknown User"}</span>{" "} {`- `} {moment(el?.createdAt).format("DD MMM YYYY")} </p> <Rating rating={el?.rate} /> <p>{el?.comment}</p> </div> )) )} </div> </div> ); } export default Reviews; شكرا
- 1 جواب
-
- 2
-
السلام عليكم. في المثال التالي، أواجه الأخطاء التالية: عندما أضيف Review معين (بين 1 و 5) فإنه يتم إرسال عدد أكبر من 5 إلى قاعدة البيانات لايتم إضافة التقييم إلى واجهة الصفحة إلا بعد التحديث الكود bookController // method POST // route api/books/:id/reviews // desc Add a book review // access Private | auth const addReview = asyncHandler(async(req, res) => { const { id } = req.params const { comment, rate } = req.body const book = await Book.findById(id) const user = await User.findById(req.userId) if (!book) { return res.status(404).json({ message: "Book Not Found" }) } const isRated = book.reviews.findIndex(m => m.user == req.userId) if (isRated > -1){ return res.status(403).send({ message: "Review Is Already Added" }); } const totalRate = book.reviews.reduce((sum, review) => sum + review.rate ,0) const finalRate = (totalRate + rate) / (book.reviews.length + 1) await Book.updateOne( { _id: id } , { $push: { reviews: { user: req.userId, username: user.name, comment, rate } }, $set: { rate: finalRate } } ) res.status(201).json({ message: "Review added successfully" }) }) Frontend apiCall // Post Review export function postReview(bookId, review) { return async (dispatch, getState) => { try { dispatch(bookActions.setLoading()) const {data} = await axios.post(`${BOOK_URL}/${bookId}/reviews`, review, { headers: { "authorization": getState().auth.user.accessToken } }); toast.success(data?.message) dispatch(bookActions.addReviews()); dispatch(bookActions.clearLoading()); } catch (error) { toast.error(error?.response?.data.message); dispatch(bookActions.clearLoading()); } }; } bookSlice const bookSlice = createSlice({ name: "book", initialState: { books: [], error: false, loading: false, }, reducers: { getBooks(state, action) { state.books = action.payload; }, findBook(state, action) { state.books = action.payload; }, addReviews(state, action) { state.books = action.payload; }, setLoading(state) { state.loading = true; }, clearLoading(state) { state.loading = false; }, setError(state) { state.error = true; }, clearError(state) { state.error = false; }, } } Component const Modal = ({ showModal, handleClose, book }) => { const [rate, setRating] = useState(0); const [comment, setComment] = useState(""); const dispatch = useDispatch(); const navigate = useNavigate(); const submitReview = (e) => { e.preventDefault(); if (comment === "") { return toast.error("Comment is required") } dispatch(postReview(book, { rate, comment })) navigate(`/${book}`) }; return ( <div className={`modal ${showModal ? "show" : ""}`}> <div className="modal-content"> <span className="close" onClick={handleClose}>×</span> <h2>Submit Your Review</h2> <form onSubmit={submitReview}> <div className="rating-input"> <label>Rating:</label> <select value={rate} onChange={(e) => setRating(e.target.value)} required> <option value="" disabled>Select a rating</option> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> <option value="4">4</option> <option value="5">5</option> </select> </div> <div className="comment"> <label>Comment:</label> <textarea value={comment} onChange={(e) => setComment(e.target.value)}/> </div> <button className='modal-btn' type="submit">Submit</button> </form> </div> </div> ); }; export default Modal; شكرا على المساعدة
-
السلام عليكم. أقدم طريقتين من كتابة الكود. الكود الأول: import React, { useEffect } from 'react' import { useDispatch, useSelector } from 'react-redux' import { fetchBooks } from '../../redux/apiCalls/bookApiCall' import { Oval } from "react-loader-spinner"; function Books({ currentPage }) { const dispatch = useDispatch() const {books, loading} = useSelector(state => state.book) useEffect(() => { dispatch(fetchBooks(currentPage)) }, [dispatch, currentPage]) if (loading) { <Oval height={120} width={120} color="rgb(247, 96, 14)" wrapperStyle={{ height: "70vh", display: "flex", alignItems: "center", justifyContent: "center", }} wrapperClass="" visible={true} ariaLabel="oval-loading" secondaryColor="#E2E2E2" strokeWidth={3} strokeWidthSecondary={3} /> } return ( <div className='books'> <h1 className='books-title'>Explore Books</h1> <div className="books-container"> { books.data?.map((book, index) => ( <div className="books-card" key={index}> <img src={book?.image.url} className='books-card-img' alt=''/> <div className="over"> <h2 className="over-title">{book?.title}</h2> <h3 className="over-auth">{book?.author}</h3> <button className="over-btn">SHOW BOOK</button> </div> </div> )) } </div> </div> ) } export default Books الكود الثاني: import React, { useEffect } from 'react' import { useDispatch, useSelector } from 'react-redux' import { fetchBooks } from '../../redux/apiCalls/bookApiCall' import { Oval } from "react-loader-spinner"; function Books({ currentPage }) { const dispatch = useDispatch() const {books, loading} = useSelector(state => state.book) useEffect(() => { dispatch(fetchBooks(currentPage)) }, [dispatch, currentPage]) return ( <div className='books'> <h1 className='books-title'>Explore Books</h1> <div className="books-container"> { loading ? (<Oval height={120} width={120} color="rgb(247, 96, 14)" wrapperStyle={{ height: "70vh", display: "flex", alignItems: "center", justifyContent: "center", }} wrapperClass="" visible={true} ariaLabel="oval-loading" secondaryColor="#E2E2E2" strokeWidth={3} strokeWidthSecondary={3} /> ) : (books.data?.map((book, index) => ( <div className="books-card" key={index}> <img src={book?.image.url} className='books-card-img' alt=''/> <div className="over"> <h2 className="over-title">{book?.title}</h2> <h3 className="over-auth">{book?.author}</h3> <button className="over-btn">SHOW BOOK</button> </div> </div> ))) } </div> </div> ) } export default Books الكود الثاني يعمل بشكل جيد حيث يتم إستدعاء Loader Component إلى حين جلب البيانات من الخادم. بينما الكود الأول لم يفعل. شخصيا أعتقد أنه لا فرق بينهما. لكن لماذا فعل الكود الثاني ولم يفعل الكود الأول. شكرا.
- 2 اجابة
-
- 2
-
أنا قمت بوضع النقطة و الدليل أن الملف يعمل بصفة جيدة لكن علامة الإعدادات في vs code غالبا ما ترمز إلى ملف مجهول ولا أدري ما سبب هذا التغير السريع لأنه منذ أسبوعين تقريبا كل شيء كان تمام
- 3 اجابة
-
- 1
-
- 3 اجابة
-
- 1