-
المساهمات
646 -
تاريخ الانضمام
-
تاريخ آخر زيارة
نوع المحتوى
ريادة الأعمال
البرمجة
التصميم
DevOps
التسويق والمبيعات
العمل الحر
البرامج والتطبيقات
آخر التحديثات
قصص نجاح
أسئلة وأجوبة
كتب
دورات
كل منشورات العضو محمود سعداوي2
-
شكرا لك @محمد_عاطف في الواقع أرى أن الحل الأنسب هو تعديل الواجهة الخلفية ليصبح بهذه الطريقة export const verifyAccount = asyncHandler(async(req, res) => { const { userId, token } = req.params // Check if user exist const user = await User.findById(userId) if (!user) { return res.status(400).json({ message: "Invalid Verification Link" }) } const verificationToken = await VerificationToken.findOne({ userId: user._id, token: token, }) if (!verificationToken) { if (user.isAccountVerified) { return res.status(200).json({ message: "Your Account is Already Verified!" }); } return res.status(400).json({ message: "Invalid Link" }); } user.isAccountVerified = true await user.save() await VerificationToken.deleteMany({ userId: user._id }); res.status(200).json({ message: "Your Account is Verified!" }) }) ففي حالتي أنا بالرغم user.isAccountVerified و !verificationToken فيظهر مكون الخطأ والسبب يعود لـ tanstack query مثلما تفضلتم بالشرح لذلك إعتمدت على تغيير منطق الواجهة الخلفية والمحافظة على الواجهة الأمامية كما هي والسبب هو التوافق مع TanStack Query والمحافظة على frontend بسيط يعتمد على TanStack Query (isLoading, isError, data) بالإضافة إلى ضمان تجربة متكاملة بين التطوير واإنتاج. شكرا جزيلا مجددا
- 12 اجابة
-
- 1
-
-
- 12 اجابة
-
- 1
-
-
تقصد هذا المكون import React, { useEffect, useState } from "react"; import { Link, useParams } from "react-router-dom"; import { useVerifyEmail } from "../lib/queries/auth.queries"; import { AiOutlineCheckCircle, AiOutlineWarning } from "react-icons/ai"; import Spinner from "../components/loaders/Spinner"; const VerifyEmail = () => { const { userId, token } = useParams(); const { mutate, data, isError, isPending } = useVerifyEmail(); console.log(" data", data) // undefined const verify = () => { if (userId && token) { console.log("👉 sending mutation with", { userId, token, data }); // data: undefined, token: defined, userId: defined mutate({ userId, token }); } } useEffect(() => { verify() }, [userId, token, mutate]); if (isPending) { return <Spinner/> } return ( <section className="flex items-center justify-center min-h-[calc(100vh-2rem)] px-4"> <div className="w-full max-w-md bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-2xl shadow-md p-6 text-center transition-all duration-300"> {isError ? ( <> <AiOutlineWarning className="text-red-500 dark:text-red-400 text-6xl mx-auto animate-pulse mb-4" /> <h1 className="text-xl font-semibold text-gray-800 dark:text-white"> error </h1> <p className="text-sm text-gray-600 dark:text-gray-300 mt-2"> Please check your verification link or request a new one. </p> </> ) : ( <> <AiOutlineCheckCircle className="text-teal-600 dark:text-teal-400 text-6xl mx-auto animate-bounce mb-4" /> <h1 className="text-xl md:text-2xl font-semibold text-gray-800 dark:text-white mb-2"> {/* {data?.message} */} Valid </h1> <Link to="/login" className="inline-block bg-teal-600 hover:bg-teal-700 text-white font-medium py-2 px-6 rounded-full transition-colors duration-300" > Login </Link> </> )} </div> </section> ); }; export default VerifyEmail;
- 12 اجابة
-
- 1
-
-
السلام عليكم. قمت ببناء مكون React للتحقق مما إذا كان المستخدم قد فعل حسابه. حسب نتيجة العملية، أريد عرض أحد المكونات التالية: 1.نجاح التحقق: <> <AiOutlineCheckCircle className="text-teal-600 dark:text-teal-400 text-6xl mx-auto animate-bounce mb-4" /> <h1 className="text-xl md:text-2xl font-semibold text-gray-800 dark:text-white mb-2"> {/* {data?.message} */} Valid </h1> <Link to="/login" className="inline-block bg-teal-600 hover:bg-teal-700 text-white font-medium py-2 px-6 rounded-full transition-colors duration-300" > Login </Link> </> 2.فشل التحقق <> <AiOutlineWarning className="text-red-500 dark:text-red-400 text-6xl mx-auto animate-pulse mb-4" /> <h1 className="text-xl font-semibold text-gray-800 dark:text-white"> error </h1> <p className="text-sm text-gray-600 dark:text-gray-300 mt-2"> Please check your verification link or request a new one. </p> </> المشكلة: في الوقت الحالي، عند فتح صفحة التحقق، يظهر أولًا مكون النجاح لبضع ثوانٍ، ثم يتحول فجأة إلى مكون الفشل، رغم أنّ عملية التحقق في قاعدة البيانات تمّت بنجاح. للمزيد من التوضيح تفضلوا: كود الواجهة الخلفية (Node.js/Express): export const verifyAccount = asyncHandler(async(req, res) => { const { userId, token } = req.params // Check if user exist const user = await User.findById(userId) if (!user) { return res.status(400).json({ message: "Invalid Verification Link" }) } const verificationToken = await VerificationToken.findOne({ userId: user._id, token: token, }) if (!verificationToken) { return res.status(400).json({ message: "Invalid Link" }); } user.isAccountVerified = true await user.save() await VerificationToken.deleteOne({ _id: verificationToken._id }); res.status(200).json({ message: "Your Account is Verified!" }) }) علما أنه في حتى حاة ظهور المكون الخاص بفشل العملية في الواجهة الأمامية فإنه تم تفعيل user.isAccountVerified = true await user.save() await VerificationToken.deleteOne({ _id: verificationToken._id }); أما بالنسبة للواجهة الأمامية api export const verifyEmailApi = async ({ userId, token }) => { try { const res = await axios.get(summaryApi.auth.verify(userId, token)) console.log("api", res.data) return res.data } catch (error) { console.error(error); throw error; } } queries export const useVerifyEmail = () => { return useMutation({ mutationFn: verifyEmailApi, onSuccess: (data) => { console.log(data) } }); } VerifEmailComponent const VerifyEmail = () => { const { userId, token } = useParams(); const { mutate, data, isError, isPending } = useVerifyEmail(); console.log(" data", data) // undefined const verify = () => { if (userId && token) { console.log("👉 sending mutation with", { userId, token, data }); // data: undefined, token: defined, userId: defined mutate({ userId, token }); } } useEffect(() => { verify() }, [userId, token, mutate]); if (isPending) { return <Spinner/> } return ( <section className="flex items-center justify-center min-h-[calc(100vh-2rem)] px-4"> // الكود الذي قمت بإدراجه سلفا </section> ); }; سؤالي: لماذا يظهر مكون النجاح أولًا لثوانٍ ثم يتحول إلى مكون الفشل، رغم أنّ التحقق في قاعدة البيانات تم بنجاح؟ وكيف يمكنني تعديل الكود الأمامي بحيث يظهر المكون الصحيح مباشرة بناءً على نتيجة العملية دون هذا التبديل الغير مرغوب فيه؟ شكرا جزيلا.
- 12 اجابة
-
- 1
-
-
السلام عليكم، في تطبيقات React.js، موضوع الحماية دائمًا من الأمور الحساسة والمهمة، وفي الغالب يكون الأسلوب المستخدم كالتالي: بعد تسجيل الدخول أو إنشاء مستخدم جديد، نقوم بالحصول على Token ثم نخزنه في الذاكرة المحلية مثل localStorage أو cookies. لكن للأسف، هذه الطريقة ضعيفة من ناحية الحماية، لأنها معرضة لهجمات مثل XSS (Cross-Site Scripting). الطريقة الثانية هي حفظ بيانات المستخدم في الذاكرة المؤقتة (in-memory) داخل كائنات React، مما يوفر حماية أكبر لأن البيانات لا تُخزن في المتصفح بشكل دائم، ولكن المشكلة هنا أن هذه البيانات تُفقد بمجرد تحديث الصفحة أو إعادة تحميلها. الحل الوسط الذي وجدته هو التالي: في النظم الخلفية (Backend)، ننشئ Token محمي باستخدام httpOnly cookie، بحيث لا يمكن الوصول إليه من جافاسكريبت في المتصفح، مما يقلل خطر هجمات XSS. مثال على إنشاء Token وتخزينه كـ httpOnly cookie: const generateToken = (res, userId) => { const token = jwt.sign({ userId }, process.env.JWT_SECRET, { expiresIn: '30d', }); // تعيين الـ JWT كـ httpOnly cookie res.cookie('jwt', token, { httpOnly: true, secure: process.env.NODE_ENV !== 'development', // لتأمين الكوكيز في بيئة الإنتاج sameSite: 'strict', // لمنع هجمات CSRF maxAge: 30 * 24 * 60 * 60 * 1000, // مدة 30 يومًا }); return token; }; ثم ننشئ نقطة نهاية (endpoint) لاسترجاع بيانات المستخدم مع بعض المعلومات الضرورية، مثل: const getMe = asyncHandler(async (req, res) => { const user = await User.findById(req.user._id).select('-password'); // استرجاع التوكن من الكوكيز const token = req.cookies.jwt; res.json({ _id: user._id, name: user.name, email: user.email, isAdmin: user.isAdmin, token, // نُرسل التوكن أيضاً للواجهة الأمامية }); }); في الواجهة الأمامية، سأستخدم مكتبة tanstack query، التي توفر طريقة مرنة وفعالة للتعامل مع الـ API، مع دعم مدمج للـ caching. سأقوم بجلب بيانات المستخدم من نقطة النهاية getMe وأحتفظ بها في الذاكرة (in-memory) داخل React. بهذه الطريقة نحقق التوازن بين: حماية البيانات لأن التوكن مخزن كـ httpOnly cookie غير قابل للوصول من جافاسكريبت مباشرةً. سهولة الوصول المستمر للبيانات في الواجهة الأمامية بدون فقدانها عند تحديث الصفحة. يسعدني جداً سماع آرائكم وملاحظاتكم، فهذه الطريقة نابعة من فكرة محلية، وبالتالي فكل ملاحظة منكم قيمة وستفيدني كثيرًا في تحسين الأمان والأداء. شكرًا لكم!
- 2 اجابة
-
- 2
-
-
المشكل بالأساس مثلما قلت هو مشاركة filters مع العناصر الفرعية وهذا شيء لابد منه لذلك كان لزاما إما تمريرها عبر props أو إستعمال global state وهو الحل الأمثل. شكرا لكم على التوضيح @Mustafa Suleiman
-
السلام عليكم. الكود التالي لصفحة ويب تعرض المنتجات مقسمة على عدة صفحات وتحتوي عنصر بحث مع قائمة جانبية للفلترة. import { useCallback, useState } from "react"; import { IoFilter, IoClose, IoAlertCircleOutline } from "react-icons/io5"; import FormFilters from "../components/products/FormFilters"; import { useFetchProducts } from "../lib/queries/productsQueries"; import Alert from "../components/Alert"; import Skeleton from "../components/loaders/Skeleton"; import Pagination from "../components/products/Pagination"; import ProductCard from "../components/products/ProductCard"; import Search from "../components/products/Search"; const ProductsPage = () => { const [filters, setFilters] = useState({ pageNumber: 1, keyword: "", category: [], minPrice: 0, maxPrice: 2000, sort: "", }); const { data, isPending: isProductsPending, isError: isProductsError, error: productsError, } = useFetchProducts(filters); const [showMobileFilters, setShowMobileFilters] = useState(false); /** * ------------------------------------------- * Search Products * ------------------------------------------- */ const handleSearchProducts = useCallback((text) => { setFilters((prev) => ({ ...prev, keyword: text.trim(), pageNumber: 1, })); }, []); /** * ------------------------------------------- * Pagination * ------------------------------------------- */ const handlePageChange = useCallback((newPage) => { setFilters((prev) => ({ ...prev, pageNumber: newPage })); }, []); /** ------------------------------------------ * Loading ------------------------------------------- */ if (isProductsPending) return <Skeleton />; return ( <div className="w-full bg-white text-gray-800 my-5 px-3"> {isProductsError && ( <Alert message={productsError.message} type="error" /> )} <div className="max-w-7xl mx-auto"> <div className="md:flex"> {showMobileFilters && ( <div className="fixed inset-0 z-50 flex"> <div className="fixed inset-0 bg-opacity-30 backdrop-blur-sm" onClick={() => setShowMobileFilters(false)} ></div> <div className="relative bg-white w-3/4 max-w-sm h-full shadow-xl animate-slide-in-left"> <button className="absolute top-3 right-4 text-2xl text-gray-600" onClick={() => setShowMobileFilters(false)} > <IoClose /> </button> {/* ------------------------------------------- Filters for Mobile ------------------------------------------- */} <FormFilters formClassName="p-4 space-y-6 mt-7" defaultValues={filters} onApplyFilters={(newFilters) => setFilters(newFilters)} /> </div> </div> )} {/* ------------------------------------------- Desktop Filters ------------------------------------------- */} <FormFilters formClassName="hidden md:block md:w-1/4 space-y-6" defaultValues={filters} onApplyFilters={(newFilters) => setFilters(newFilters)} /> <div className="md:w-3/4 md:pl-8 mx-auto"> {/* ------------------------------------------ Products Searching (Mobile & Desktop) ------------------------------------------- */} <div className="flex items-center justify-center space-x-2 mb-3"> <div className="md:hidden"> <button onClick={() => setShowMobileFilters(true)} className="flex items-center text-white bg-[#F8AD47] font-semibold p-3 rounded-md cursor-pointer" > <IoFilter size={20} /> </button> </div> <Search onSearch={handleSearchProducts}/> </div> {/* ------------------------------------------ Display Products ------------------------------------------- */} <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6"> {data.products?.length > 0 ? ( data.products.map((product) => ( <ProductCard key={product._id} product={product} /> )) ) : ( <div className="col-span-full flex flex-col items-center justify-center text-center p-6 border border-dashed border-gray-300 rounded-xl text-gray-500 dark:text-gray-400"> <IoAlertCircleOutline className="text-4xl mb-2" /> <p className="text-lg font-medium">No products found</p> <p className="text-sm">Try adjusting your filters or search term.</p> </div> )} </div> {/* ------------------------------------------- Pagination ------------------------------------------- */} {data?.page && parseInt(data?.pages) > 1 && ( <Pagination currentPage={data?.page} totalPages={data?.pages} onPageChange={handlePageChange} /> )} </div> </div> </div> </div> ); }; export default ProductsPage; المشكل هو عند كل تغيير في البحث مثلا يحصل rerender لقائمة الفلترة والعكس صحيح وهذا يكلف ثمنا باهضا على الأداء. قمت باستخدام useCallback useMemo React.memo لكن لم يتغير شيء. هل من حلول تقوم بتحسين الأداء شكرا
- 2 اجابة
-
- 1
-
-
السلام عليكم ورحمة الله وبركاته، عند رفع صورة في مشروع مبني باستخدام Express وTypeScript، كنت أتّبع الخطوات التالية: رفع الصورة مؤقتًا على الخادم المحلي باستخدام Multer. رفع الصورة إلى Cloudinary والحصول على كلٍّ من publicId وsecureUrl. حذف الصورة من المسار المحلي بعد رفعها. وقد كانت هذه الطريقة تعمل بشكل جيد أثناء مرحلة التطوير المحلي (Development). لكن عند نشر المشروع على منصات استضافة مجانية مثل Render، لم تعد العملية تنجح، رغم أن عملية البناء (Build) تتم بنجاح. لا أعلم ما إذا كانت المشكلة ناتجة عن الطريقة التي استخدمتها، وأتساءل إن كانت هناك حلول بديلة تضمن عمل رفع الصور بشكل صحيح في بيئة الإنتاج (Production)؟ شكرا لكم.
- 1 جواب
-
- 1
-
-
شكرا. المشكل الحالي: بعد رفع المشروع إلى البيئة الإنتاجية، لم أعد قادرًا على تغيير صورة الملف الشخصي للمستخدم، بالرغم من أن العملية تعمل بشكل سليم تمامًا في بيئة التطوير (development). ✅ لا تظهر أي أخطاء سواء في الواجهة الأمامية (frontend) أو الخلفية (backend). ✅ نفس الكود المستخدم في التطوير تم رفعه كما هو إلى الإنتاج. الكود كاملا الواجهة الخلفية: profile.ts /** * @method PUT * @route /api/profile/:id/profile-photo * @desc Update user profile (name & bio) * @access private (only user himself) */ export const updateProfilePhoto = async ( req: Request, res: Response ): Promise<void> => { try { // Check if the user is authorized to update this profile if (req.user.id !== req.params.id) { res.status(403).json({ message: "Unauthorized: You are not allowed to update this profile." }); return } // Check if an image file was uploaded if (!req.file) { res.status(400).json({ message: "No image file uploaded." }) return } // Build the local path to the uploaded image const imagePath = path.join(__dirname, ../images/${req.file.filename}) // Upload the image to Cloudinary const uploadResult = await cloudinaryUploadImage(imagePath) // Remove the local image file after upload await fs.unlink(imagePath); // Retrieve the user from the database const profile = await prisma.user.findUnique({ where: { id: req.user.id } }) if (!profile) { res.status(404).json({ message: "User not found" }); return } // If the user already has a profile picture, remove it from Cloudinary const profilePicture = profile.profilePicture as { publicId: string; secureUrl: string }; if (profilePicture?.publicId) { await cloudinaryRemoveImage(profilePicture.publicId); } // Update the user's profile with the new profile picture const updatedProfilePhoto = await prisma.user.update({ where: { id: req.user.id }, data: { profilePicture: { publicId: uploadResult.public_id, secureUrl: uploadResult.secure_url } }, select: { id: true, name: true, profilePicture: true } }); // Return a success response with updated user info res.status(200).json({ updatedProfilePhoto, message: "Profile photo updated successfully." }); } catch (err) { handleError(res, err as Error); } }; middlewares/cloudinary.ts *************************** import { v2 as cloudinary } from 'cloudinary'; cloudinary.config({ cloud_name: process.env.CLOUDINARY_CLOUD_NAME, api_key: process.env.CLOUDINARY_API_KEY, api_secret: process.env.CLOUDINARY_API_SECRET }) export const cloudinaryUploadImage = async(fileToUpload: string) => { try { const data = await cloudinary.uploader.upload(fileToUpload, { resource_type: 'auto', }) return data } catch (error) { console.log(error) throw new Error('Internal Server Error (cloudinary)') } } export const cloudinaryRemoveImage = async(imagePublicId: string ) => { try { const result = await cloudinary.uploader.destroy(imagePublicId) return result } catch (error) { console.log(error) throw new Error('Internal Server Error (cloudinary)') } } middlewares/upload.ts ********************* import path from "path"; import multer from "multer"; import { fileURLToPath } from "url"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); // Photo Storage const photoStorage = multer.diskStorage({ destination: function (req, file, cb) { cb(null, path.join(__dirname, "../images")); }, filename: function (req, file, cb) { if (file) { cb(null, new Date().toISOString().replace(/:/g, "-") + file.originalname); } else { cb(new Error("File upload error"), "") } }, }); // Photo Upload Middleware export const photoUpload = multer({ storage: photoStorage, fileFilter: function(req, file, cb) { if (file.mimetype.startsWith("image")) { cb(null, true) } else { cb(new Error("Unsupported File Format")) } }, limits: { fieldSize: 1024 * 1024 * 5 } }) الواجهة الأمامية EditProfileImage.tsx ********************* import { FaCamera } from "react-icons/fa"; import { useUpdateProfilePhoto } from "../../hooks/useProfile"; import { useAuthStore } from "../../store/auth.store"; import { toast } from "react-toastify"; import Spinner from "../Spinner"; import { defaultAvatar } from "../../utils/constantes"; const EditProfileImage = () => { const { user, token, setUser } = useAuthStore(); const { mutate, isPending } = useUpdateProfilePhoto(); const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => { if (e.target.files?.[0]) { updateProfilePhoto(e.target.files[0]); } }; const updateProfilePhoto = (selectedFile: File) => { if (!token || !user) return mutate( {file: selectedFile, token, id:user?.id}, { onSuccess: (data) => { setUser({ ...user, photoProfile: data?.updatedProfilePhoto.profilePicture.secureUrl, }); toast.success(data?.message) }, onError: (err) => { console.log(err) toast.error('An unexpected error occurred.') } }) }; if (isPending) { return ( <Spinner /> ); } return ( ....... ); }; export default EditProfileImage; ****************************** hooks/useUpdateProfilePhoto ****************************** export const useUpdateProfilePhoto = () => { return useMutation({ mutationFn: ({ file, token, id, }: { file: File; token: string; id: string; }) => updateProfilePhotoApi(file, token, id), }); }; ************************ api/profile.api.ts *********************** export const updateProfilePhotoApi = async ( file: File, token: string, id: string ) => { try { const formData = new FormData() formData.append("image", file) const res = await axios.put( ${process.env.REACT_APP_API_URL}/profile/${id}/profile-photo, formData, { headers: { Authorization: Bearer ${token}, }, withCredentials: true, } ); return res.data } catch (error) { console.log(error) } };
-
السلام عليكم. أواجه مشكل في رفع التطبيق التالي على render. package.json { "name": "chat-app-backend", "version": "1.0.0", "main": "index.js", "type": "module", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "node dist/index.js", "server": "tsx watch index.ts", "build": "prisma generate && tsc", "postinstall": "prisma generate" }, "author": "Mahmoud Saadaoui", "license": "ISC", "description": "", "dependencies": { "@prisma/client": "^6.6.0", "bcrypt": "^5.1.1", "cloudinary": "^2.6.1", "cors": "^2.8.5", "dotenv": "^16.5.0", "express": "^4.21.2", "express-async-errors": "^3.1.1", "jsonwebtoken": "^9.0.2", "multer": "^2.0.0", "nodemailer": "^7.0.3", "socket.io": "^4.8.1", "zod": "^3.24.4" }, "devDependencies": { "@types/bcrypt": "^5.0.2", "@types/express": "^5.0.1", "@types/jsonwebtoken": "^9.0.9", "@types/multer": "^1.4.12", "@types/node": "^22.16.0", "@types/nodemailer": "^6.4.17", "@types/web-push": "^3.6.4", "prisma": "^6.6.0", "ts-node": "^10.9.2", "tsx": "^4.19.3", "typescript": "^5.8.3" } } tsconfig.json { "compilerOptions": { "outDir": "dist", "target": "esnext", "lib": ["dom", "dom.iterable", "esnext"], // "module": "commonjs", "module": "esnext", "moduleResolution": "node", "strict": true, "forceConsistentCasingInFileNames": true, "esModuleInterop": true, "resolveJsonModule": true, "isolatedModules": true, "jsx": "preserve", "baseUrl": ".", "paths": { "@/*": ["src/*"] }, "incremental": true, "skipLibCheck": true }, "include": ["index.ts", "**/*.ts"], "exclude": ["node_modules"] } تنظيم الملفات الخطأ ملاحظة عندما أقوم بـ يظهر بوضوح الملف شكرا لكم.
- 2 اجابة
-
- 1
-
-
هل تمت إضافة مسار جديد في دورة الجافاسكريبت. مسار PWA.
- 2 اجابة
-
- 2
-
-
السلام عليكم. لاحظت أن بعض مشاريع next.js تعتمد على express.js في بناء الواجهة الخلفية. ماجدوى هذا الخيار خاصة وأن next.js يوفر خادما. أو بالأحرى إن كان next.js يوفر خادما لماذا يتم اللجوء إلى خادم خارجي وهل ذلك يؤثر قوة التطبيق. أم من الأفضل إستخدام خادم خارجي مع رياكت خاصة بعد التحديثات التي حصلت مؤخرا. شكرا لكم.
- 3 اجابة
-
- 2
-
-
السلام عليكم. أود أفكار مشاريع تكون قريبة من الواقع لتعزيز مهاراتي في الذكاء الاصطناعي التلقائي علما واني ساستخدم next.js شكرا لكم
-
السلام عليكم. أريد بناء تطبيق محلي يوفر واجهة حقول تتيح البحث أو الإضافة أو التعديل .... (مثل التي يوفرها access أو excel VBA) سيستعمل هذا التطبيق هذا التطبيق مجموعة من الأفراد الذين ليست لهم أي صلة بالبرمجة. بماأني مطور ويب جافاسكريبت فأهدف لتوظيف مهاراتي في SQL لبناء هذا التطبيق. أبحث عن أفضل الحلول الممكنة لبناء هذا التطبيق. شكرا.
- 1 جواب
-
- 2
-
-
السلام عليكم، من المعلوم أن مكتبة TanStack Query توفر مرونة كبيرة في التعامل مع البيانات القادمة من الخادم. مع ذلك، لا يُفضل استخدامها مع مكتبات أخرى لإدارة حالة التطبيق مثل Zustand و Redux Toolkit، حيث قد يؤدي ذلك إلى تعقيد غير ضروري. واجهت مشكلة عند تسجيل الدخول إلى التطبيق ثم الانتقال إلى صفحة أخرى، إذ كان من الضروري تخزين البيانات القادمة من الخادم في الذاكرة المحلية للمتصفح لاستخدامها في الحماية والتحقق. لحل هذه المشكلة، استخدمت createContext. المشكلة الأخرى أنني لم أجد من استخدم هذا الحل مسبقًا، لذا أود الاستفسار عن مدى فاعليته، وهل هناك حل أفضل؟ شكرًا لكم.
- 2 اجابة
-
- 1
-
-
لم يتغير شيء كما أني قمت بأضافة البيانات إلى الذاكرة المحلية للمتصفح بالطريقة التالية export const useLoginMutation = () => { return useMutation({ mutationFn: async (data) => await loginApi(data), onSuccess: (data) => { localStorage.setItem("user", JSON.stringify(data)) console.log("User stored in localStorage:", data); }, }); };
- 4 اجابة
-
- 1
-
-
السلام عليكم لدي مشكلة في التنقل عند إنشاء المسارات المحمية. بعد تسجيل الدخول وتخزين بيانات المستخدم في localStorage، لا يتم توجيهي إلى لوحة التحكم (dashboard). إليك الكود الخاص بي، بما في ذلك App.js، وroutes.js، وLoginForm.js. علماً بأنه قبل تطبيق المسارات المحمية، كان كل شيء يعمل بشكل طبيعي. App.js function App() { return ( <Router/> ); } routes.js const user = JSON.parse(localStorage.getItem("user")) const router = createBrowserRouter([ { path: "/", element: !user ? <LoginPage /> : <Navigate to="/dashboard" /> }, { path: "/dashboard", element: user ? <DashboardLayout /> : <Navigate to="/" />, children: [ { index: true, element: <Dashboard /> }, ... ] } ]); export default function Router() { return <RouterProvider router={router} />; } LoginForm.js const LoginForm = () => { const navigate = useNavigate(); const { formData, handleChange } = useForm({ unique_identifier: "", password: "", }, ["unique_identifier"]) const { mutate, isPending, isError, error } = useLoginMutation(); const submitHandler = async (e) => { e.preventDefault(); mutate( formData, { onSuccess: () => navigate("/dashboard") } ); }; return ( <> {isError && <Alert message={error} />} .... My Form .... </> ); }; أعتقد أن المشكل يتعلق بعدم إعادة تحديث الحالة (state) عند تسجيل الدخول، مما يمنع إعادة توجيه المستخدم إلى لوحة التحكم (dashboard). لكن أعتقد أنه ليس من الجيد إضافة تطبيقات لإدارة الحالة مثل zustand. أرجو المساعدة لأجد الحل الأنسب.
- 4 اجابة
-
- 1
-
-
السلام عليكم. عند إرسال البيانات للخادم const submitHandler = async (e) => { e.preventDefault(); mutate( { unique_identifier, password }, { onSuccess: () => navigate("/dashboard") } ); }; لاتظهر علامة التحميل spinner في الكود التالي <button type="submit" className="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 rounded-lg transition duration-300 ease-in-out" disabled={isLoading} > {isLoading ? ( <ScaleLoader color="#ffffff" height={12} width={3} /> ) : ( "Login" )} </button> loginApi import axios from "axios"; export const loginApi = async(data) => { try { const res = await axios.post( `${process.env.REACT_APP_USER_URL}/login`, data ); return res.data; } catch (error) { throw error.response.data.message } } useLoginMutation import { useMutation } from "@tanstack/react-query"; import { loginApi } from "../api/userApi"; export const useLoginMutation = () => { return useMutation({ mutationFn: async (data) => await loginApi(data), onSuccess: (data) => localStorage.setItem("token", data.token), }); }; شكرا.
- 3 اجابة
-
- 1
-
-
السلام عليكم، أرغب في تطوير تطبيق لمتابعة العمال في شركة معينة، مستفيدًا من خبرتي في SQL باستخدام pgAdmin وPostgreSQL. حيث يمكنني عبر استعلامات SQL: عرض جميع العمال. عرض بيانات عامل معين. استخراج العمال ذوي وضعيات إدارية خاصة. تعديل بيانات العمال. لكن المشكلة أن المستخدم النهائي لهذا التطبيق لا يمتلك أي معرفة باستعلامات SQL. كيف يمكنني بناء واجهة تفاعلية تتيح لهذا المستخدم الاستفادة من التطبيق بسهولة؟ هل أحتاج إلى استخدام برامج أخرى لتحقيق ذلك؟ ما أريده يشبه Excel، حيث أقوم بتحديد العمليات (مثل إيجاد أكبر قيمة)، ثم يقوم المستخدم بإدخال البيانات ليحصل على النتائج تلقائيًا. أتمنى أن يكون سؤالي واضحًا، وشكرًا لكم. ملاحظة: ليست لدي خبرة ببناء تطبيقات سطح المكتب
- 2 اجابة
-
- 2
-
-
السلام عليكم. المعلوم أن UML Diagrams مبني على البرمجة الكائنية التوجه على عكس node.js. ماهي الطريقة المثلى لإستخدام UML Diagrams في مشروع nodejs شكرا
- 2 اجابة
-
- 2
-