امروز پس از گذشت حدود ۲ ماه و نیم ضبط و داوری، همرویش مفتخر است که فصل ششم از آموزش ساخت فروشگاه فول استک با جنگو و ری اکت را به شما عرضه کند.
در این فصل ما از ساخت فروشگاه اینترنتی با django به احراز هویت کاربران در سمت فرانت اند میپردازیم. از سیستمی که در فصل پنجم برای این کار ساخته بودیم استفاده کردیم. حال بدون اتلاف وقت نگاهی به این آموزش میاندازیم تا با کلیات این آموزش آشنا شوید.
این آموزش بخشی از بسته جامع ساخت فروشگاه با جنگو و ری اکت (+) است.
شما میتوانید بسته جامع با با مجموع قیمت کمتر از این لینک (+) تهیه کنید یا این مجموعه را فصل به فصل دریافت و تماشا کنید.
فهرست فصلبهفصل آموزش ساخت فروشگاه جنگو/ریکت
-
- ساخت فروشگاه آنلاین با Django و Reacct ـــ فصل ۱: ری اکت
- ساخت فروشگاه آنلاین با Django و Reacct ـــ فصل ۲: جنگو رست
- آموزش فروشگاه جنگو و ری اکت – فصل ۳: مدیریت وضعیت با Redux
- آموزش ساخت فروشگاه فول استک با جنگو و ری اکت – فصل ۴: سبد خرید
- آموزش فروشگاه آنلاین با جنگو پایتون و ری اکت – فصل ۵: اعتبارسنجی
- آموزش ساخت فروشگاه فول استک با جنگو و ری اکت – فصل ۶: احراز هویت
- آموزش ساخت فروشگاه فول استک با جنگو و ری اکت – فصل ۷: ثبت سفارش
- آموش ساخت فروشگاه فول استک با جنگو و ری اکت ــ فصل ۸: درگاه پرداخت
- آموزش ساخت فروشگاه فول استک با جنگو و ری اکت ــ فصل ۹: انتشار آنلاین
این آموزش در یک نگاه:
از همان درس اول با ساخت نحوه ورود کاربر به سیستم، کار را به صورت عملی شروع کردیم. ریداکس را برای این کار تنظیم و صفحه ورود را ساختیم. پس از آن امکان خروج کاربر را هم ایجاد کردیم. اکنون کاربران امکان ورود و خروج از سیستم را دارند اما کاربران جدید چطور؟
تنها راه ثبت نام آنها از طریق پنل مدیریت است. پس امکان ثبت نام را در دو درس مجزا از هم تکمیل کردیم. اکنون کاربران جدید هم میتوانند ثبت نام کنند.
صفحهای به اسم پروفایل ایجاد کردیم تا کاربران بتوانند اطلاعات خود را در آن ببینند و یا بروز کنند. در درسی به مدیریت پیامها پرداختیم و تا حدی باگهای کوچکی که در سمت فرانت اند داشتیم را بر طرف نمودیم.
در درس فرایند تایید ایمیلی در جنگو به این پرداختیم که اگر که ما بخواهیم تایید ایمیلی یا همان ( Email Verfication ) را بر روی پروژه پیاده سازی کنیم فرایند به چه صورت میشود. این فرایند چه تفاوتی با ثبت نام عادی دارد؟
در سه الی چهار درس با یکدیگر تایید ایمیلی را روی فروشگاه اعمال کردیم. از این به بعد کاربران باید برای ثبت نام و استفاده از فروشگاه ایمیل خود را تایید کنند تا حسابشان فعال شود.
در درس ۱۶ یاد گرفتیم که چطور ایمیل را در صورتی که روی میزبان محلی ( Local Host ) هستیم به شکل واقعی ارسال کنیم. از این درس به بعد، به بهتر کردن فروشگاه و برطرف کردن باگهای موجود پرداختیم.
به عنوان مثال در درسهای ۱۷ تا ۱۹ به Access Tokenهای مرده ( expired ) در سمت فرانت-اند و تازه سازی آن با استفاده از Refresh Token پرداختیم. در نهایت متوجه باگ احتمالی در jwt شدیم که آن را با ابزار Throttling در جنگو رست رفع کردیم. در نهایت به این فصل پایان دادیم.
این آموزش بینظیر است زیرا:
- این آموزش پروژه محور است.
- مباحث این آموزش پیشرفتهتر است.
- در این آموزش با سیستم JWT که روشی نوین در احراز هویت کاربران است کار میکنیم.
پیشنیاز
- آموزش مقدماتی ری اکت (+)
- فصلهای اول (+) و دوم (+) و سوم (+) و چهارم (+) و پنجم (+) آموزش فروشگاه با جنگو و ری اکت
کلیدواژگان
آموزش فروشگاه فول استک با جنگو | فول استک با جنگو | آموزش ساخت فروشگاه فول استک | ساخت فروشگاه اینترنتی با جنگو | فروشگاه اینترنتی با جنگو | فروشگاه با جنگو | ساخت فروشگاه اینترنتی با django | ساخت فروشگاه اینترنتی با جنگو | فروشگاه اینترنتی با جنگو | فروشگاه با جنگو | ساخت فروشگاه با ریکت | فروشگاه فول استک با ری اکت
امین دهقان (خریدار محصول) –
سلام مجدد و تشکر از پاسخ گویی شما
بله موضوع قبلی حل شد
این مشکل بنده هم حل شد اگر امکان داشته باشه تو نامگذاری متغییر ها کمی وسواس بیشتر به خرج بدید
برای مثال شما userLogin رو هم توی انبار و هم توی کلاس تعریف کردید
و واقعا راه رو برای مهندسی معکوس یا درک دقیق مطلب پیچیده تر می کنه
مخصوصا برای ما پیر مرد های دات نت کار 🙂
از وقتی که گذاشتید ممنونم 🙂
ابوالفضل حسن زاده –
سلام وقت شما بخیر اقای دهقان . خدا رو شکر که مشکلتون حل شد . بله کاملا درست میفرمایید از این به بعد نامگذاری متغیر ها رو با وسواس و دقت بیشتری انجام میدم . خیلی ممنون از شما ❤❤.
امین دهقان (خریدار محصول) –
سلام روز به خیر
const userLogin=useSelector(state =>state.userLogin)
const {error,userInfo,loading}=userLogin
استاد واقعا من هر کاری کردم هرچقد آموزش رو نگاه کردم حتی مهندسی معکوس کردم متوجه نشدم
این دو خط رو از کجا آوردید
میشه خواهش کنم بفرمایید
error userInfo oading userLogin state منظورتون از تمام این کلمات را بفرمایید؟ سپاس
ابوالفضل حسن زاده –
سلام آقای دهقان وقت شما هم بخیر . اگر که منظورتون رو درست متوجه شده باشم ، این کد رو ما در فایل loginScreen.js نوشتیم ( این تا اینجا ). در واقع با این کد ما اون کلیدهایی که در انبار ریداکس تعریف کرده بودیم ( تابع ریدوسر userLoginReducer کلید ها رو اینجا تعریف کردیم )، داریم واکشی میکنیم که ببینیم چه مقدارهایی دارند تا مثلا اگر که loading مقدارش true هست ، یه انیمیشن به نشانه بارگذاری نمایش بدیم . یا مثلا اگر که userInfo مقدار درست داره ( یعنی توکن داره ، اسم و نام کاربری داره و…. ) اون وقت یعنی کاربر لاگین کرده . یا اگر که error مقدار داره یعنی در حین ورود ( درواقع منظور از ورود اینجا دریافت access و refresh توکن هستش ) به مشکل خورده و اون وقت باید یه پیام مناسب بهش نمایش بدیم . state رو هم ما یه متغیر به تابع useSelector میدیم ( شما اینجوری تصور کنید ) بعد این کل انبار ریداکس رو میریزه داخل این متغیر بعد اون موقع با اون کلیدی که توی انبار ذخیرش کردیم داخل فایل store.js به واسطه این متغیر خیلی راحت تر میتونیم صداش بزنیم . اصلا میتونه به این صورت باشه useSelector(x => x.userLogin) هیچ تفاوتی نداره ولی خب ما به جای x ، state رو پاس دادیم تا کدمون تمیز و خوانا باشه . دلیل نوشتنش همین بود .
پی نوشت :
مشکل قبلی تون حل شد ؟؟
امین دهقان (خریدار محصول) –
سلام استاد گرامی با تشکر از زحمات شما و تشکر از شما
این کد مربوط به POST هست که در action نوشتم
dispatch({type: USER_LOGIN_REQUEST})
const config={header:{‘Content-type’:’application/json’}}
const { data } = await axios.post
(
‘http://172.16.45.198/api/Users/UserLogin’,
{‘UserName’:UserName,’UserPassword’:UserPassword}, config,
)
dispatch({
type:USER_LOGIN_SUCCESS,
payload :data,
})
قبلش عرض میکنم که در بخش GET هیچ مشکلی ندارم
ولی در این بخش با خطای NETWORK ERROR مواجه میشم
نکته: من این درخواست رو در پستمن تست کردم و خطایی نداشتم
ابوالفضل حسن زاده –
سلام اقای دهقان وقت شما بخیر . اول از همه اینکه خیلی عذرخواهی میکنم جوابتون دیر شد و دوم اینکه ما username password رو که ارسال میکنیم تا access , refresh token دریافت کنیم باید با کلید های username , password باشه . یکی از مشکلات میتونه از اینجا باشه الان شما به این شکل نوشتید {‘UserName’:UserName,’UserPassword’:UserPassword}, باید تبدیل به این حالت بشه {‘username’:username, ‘password’:password} شما این حالت رو هم بررسی کنید اگر درست نشد کدتون رو روی گیت هاب قرار بدید و لینکش رو اینجا قرار بدید تا بررسی کنم . این لینک هم میتونه به شما کمک کنه .
mehdi mahdavi (خریدار محصول) –
سلام تشکر از زحمات شما یه سوال داشتم تااین مرحله پیش اومدم وقتی صفحه را رفرش میکنم یوزر لوگ اوت میشه ممنون میشم راهنمای بفرمایید
ابوالفضل حسن زاده –
سلام متشکرم از محبت شما . ببینید زمانی که شما صفحه رو reload یا refresh میکینید ریداکس شما خالی میشه . احتمالا داخل فایل store.js در بخش initialstate متغیریی که برای اولین بار به ریداکس مقدار میده مشکل دارید و یا در جایی که لاگین میکنید و اطلاعات کاربر رو در localstorage ذخیره مکنید مشکل دارید و یا اینکه در هر دو جا درست عمل میکنید ولی در بخش initialstate دارید با نام اشتباه اطلاعات کاربر رو از localstorage میخونید . اگر که اشتباه نکنم در دوره اطلاعات کاربر رو با کلید userInfo ذخیره کردیم . شما این احتمالات رو بررسی کنید باز اگر که مشکل حل نشد بازگو کنید که من بیشتر بررسی کنم.
ذخیره اطلاعات کاربر در مرورگر
مقدار دهی اولیه ریداکس از اطلاعات ذخیره شده کاربر در مرورگر
محمدرضا گوشکی (خریدار محصول) –
سلام استاد عزیز خسته نباشید ممنون از دوره عالی
من هاست پایتونی دارم و در حال حاضر بخش بک اند که جنگو هست رو دیپلوی کرده ام. سوال اینجاست برای دیپلوی کردن بخش فرانت اند پروژه که با ری اکت هست باید هاست جدا تهیه کنم یا روی همان فضا پایتونی میتوان بخش فراند اند را مستقر کرد؟
امین اجاقی (خریدار محصول) –
با سلام و درود خدمت استاد بزرگ و گرامی مصطفی آصفی عزیز استادم که مرا تا مرحله یک برنامه نویس فول استک شدن بسیار یاری رسانده است و من همیشه بدنبال آموزش های شما و همراه بودن با شما در تمام زمان ها هستم و سلام خدمت استاد و دوست و هم شاگردی عزیزم ابوالفضل حسن زاده عزیز و گرامی من پس از کمال در رشد دانشم در برنامه نویسی در مسیر های مختلف بسیار زیباست که بالاخره در یک شرکت که با زبان آنگولار و دات نت کار می کند شغل پیدا کردم یعنی علاوه بر تمام دروسی که با استاد عزیزم مصطفی آصفی و شما و استادان دیگری در همه زمینه های وب گذراندم آنگولار هم یاد گرفتم تا در این شرکت به کار پرداختم و بسیار شادم و شکر گزار خدای بزرگ و متعال و همچنین تمام دروسی که از گذشته شروع کردم را هم مخصوصا دروسی که از هم رویش می آید را دنبا می کنم و دانشم را گسترش می دهم و همینطور این دو دوره ی جدیدی که از این دوره از آموزش ها قرار دادید یعنی 6 و 7 را خریداری کرده ام تا در یک زمان مناسب شروع به یادگیری کنم زیرا هم رویش یک آموزشگاه اینترنتی بسیار مردمی است که با نور خدا و دل هایی بسیار نورانی که از سوی خداست دلی مانند دل پاک و آرام استاد عزیزم مصطفی آصفی که بسیار زیبا و دوستانه و بسیار نیکو در مسیر رشد دانش مردم ایران که خواهران و برادران هستیم این چنین کوشا هستین و از خدای متعال برکات بسیار از آشسمان نیکو هایشان برایتان می طلبم و کمال موفقیت تان از او خواستارم برکت خدا بر شما و عشق زندگیتان و خانواده ها و دوستان و آشناینتان.
iman (خریدار محصول) –
استاد عزیز لطفا برای درگاه پرداخت بحثهای تکنیکی هم که در پروژه واقعی حتما رعایت کنیم رو هم ذکر کنید چون حالت معمولی اش زیاده اصل نکات تکنیکی هست که تو هر آموزشی پیدا نمیشه . مثلا اگر یک سبد خرید داشته باشیم در موبایل و بعد از مدتی با لپ تاپ محصول جدیدی اضافه کنیم . موارد قبلی در سبد خریدمان تعیین تکلیف بشود و از کاربر پرسیده شود به سبد اضافه شود یا موارد قبلی حدف شود. یا از آن مهمتر وقتی یک محصول در سبد داریم و دونفر همزمان درخواست خرید نهایی میزنند و به درگاه پرداخت میروند نفری که زودتر خرید رو زده و به درگاه رفته محصول برایش رزرو شود و در صورت نهایی شدن خرید که تعداد محصول ناموجود شود ولی اگر انصراف از خرید شود محصول از رزور برگشته و دوباره به تعدا محصولات موجود اضافه شود. یا مواردی چون ایجاد تخفیفات دوره ای یا خرید با کپن تخفیف
ابوالفضل حسن زاده –
سلام به شما . انشالله چشم حتما . فروشگاه رو که ساختیم در قالب فصل های کوچولو کوچولو این مشکلات رو هم حل میکنیم و اون رو تبدیل به یک فروشگاه حرفه ای و واقعی خواهیم کرد.
رضا (خریدار محصول) –
درود بر شما
یک نکته ای رو خواستم یاد آور بشم:
در جایی اومدید و برای تعریف متغیر از var استفاده کردید که این کار منسوخ شده هستش و پیشنهاد شده به دلایل امنیتی و .. استفاده نشه و به جاش از let استفاده بشه.
و راستی من با یک سری تغییرات کوچیک تونستم پروژه رو روی آخرین ورژن ری اکت یعنی 18 و کتابخونه هاش اجرا کنم. که البته در ورژن جدید ریداکس پیشنهاد شده از ریداکس تولکید استفاده بشه اما خب دستورات قدیمی هم به خوبی کار میکنن.
“dependencies”: {
“@hookform/resolvers”: “^2.8.10”,
“@react-icons/all-files”: “^4.1.0”,
“@testing-library/jest-dom”: “^5.16.4”,
“@testing-library/react”: “^13.3.0”,
“@testing-library/user-event”: “^14.2.0”,
“axios”: “^0.27.2”,
“bootstrap”: “^5.1.3”,
“dayjs”: “^1.11.3”,
“http-proxy-middleware”: “^2.0.6”,
“jwt-decode”: “^3.1.2”,
“react”: “^18.1.0”,
“react-bootstrap”: “^2.4.0”,
“react-dom”: “^18.1.0”,
“react-hook-form”: “^7.32.0”,
“react-icons”: “^4.4.0”,
“react-redux”: “^8.0.2”,
“react-router-bootstrap”: “^0.26.1”,
“react-router-dom”: “^6.3.0”,
“react-scripts”: “^5.0.1”,
“redux”: “^4.2.0”,
“redux-devtools-extension”: “^2.13.9”,
“redux-thunk”: “^2.4.1”,
“web-vitals”: “^2.1.4”,
“yup”: “^0.32.11”
},
“scripts”: {
“start”: “react-scripts start”,
“build”: “react-scripts build”,
“test”: “react-scripts test”,
“eject”: “react-scripts eject”
},
“eslintConfig”: {
“extends”: [
“react-app”,
“react-app/jest”
]
},
“browserslist”: {
“production”: [
“>0.2%”,
“not dead”,
“not op_mini all”
],
“development”: [
“last 1 chrome version”,
“last 1 firefox version”,
“last 1 safari version”
]
}
}
در پایان من صفحه ی آپدیت پروفایل(profileScreen) رو با react-hook-form ساختم و اینجا قرارش میدم تا دوستان اگه مایل بودن استفاده کنن.
import React, {useEffect, useState} from ‘react’;
import {Button, Col, Form, Row} from “react-bootstrap”;
import * as yup from “yup”;
import {yupResolver} from “@hookform/resolvers/yup”;
import {useForm} from “react-hook-form”;
import {useDispatch, useSelector} from “react-redux”;
import {getUserDetailAction, updateUserProfileAction, userLogoutAction} from “../actions/userActions”;
import {useNavigate} from “react-router-dom”;
import {USER_UPDATE_PROFILE_RESET} from “../constants/userConstans”;
import Loader from “../components/Loader”;
import Message from “../components/Message”;
const ProfileScreen = () => {
const navigate = useNavigate()
const [name, setName] = useState(”);
const [email, setEmail] = useState(”);
const [successUpdate, setSuccessUpdate] = useState(”)
const nameRegex = /^[a-zA-Z0-9]+$/;
const emailRegex = /^\w+([-]?\w+)*@\w+([-]?\w+)*(\.\w{2,3})+$/
const password = /^(?=.*[0-9])(?=.*[!@#$%^&*])[a-zA-Z0-9!@#$%^&*]{6,16}$/
const validationSchema = yup.object().shape({
name: yup.string()
.required()
.matches(nameRegex),
email: yup.string()
.required()
.matches(emailRegex),
password: yup.string()
.required(‘Password is required’)
.min(8)
.matches(password),
confirmPassword: yup.string()
.required(‘Confirm Password is required’)
.oneOf([yup.ref(‘password’)], ‘password must match’)
});
const {register, control, handleSubmit, formState: {errors}, reset} = useForm({
resolver: yupResolver(validationSchema),
defaultValues: {name: name, email: email}
})
const dispatch = useDispatch()
const userLogin = useSelector(state => state.userLogin)
const {userInfo} = userLogin
const userDetails = useSelector(state => state.userDetails)
const {user} = userDetails
console.log(‘its user’, user)
const errorOfUserDetails = userDetails.error
const loadingOfUserDetails = userDetails.loading
const userUpdateProfile = useSelector(state => state.userUpdateProfile)
const {success} = userUpdateProfile
const errorOfUserUpdateProfile = userUpdateProfile.error
const loadingOfUserUpdateProfile = userUpdateProfile.loading
let loading = false
let error = ”
if (loadingOfUserDetails || loadingOfUserUpdateProfile) {
loading = true
}
if (errorOfUserDetails) {
error = errorOfUserDetails
} else if (errorOfUserUpdateProfile) {
error = errorOfUserUpdateProfile
}
const TE = “Token is invalid or expired”
useEffect(() => {
if (errorOfUserDetails === TE || errorOfUserUpdateProfile === TE) {
dispatch(userLogoutAction())
navigate(‘/login?redirect=/profile’)
}
if (!userInfo) {
navigate(‘/login’)
} else {
if (!user || !user.name || success) {
dispatch({type: USER_UPDATE_PROFILE_RESET})
dispatch(getUserDetailAction(‘profile’))
} else {
setName(user.name)
setEmail(user.email)
}
}
reset({name: name, email: email})
}, [navigate, userInfo, user, dispatch, success, name, email, reset, errorOfUserDetails, errorOfUserUpdateProfile]);
const submitForm = (data) => {
const name = data.name
const email = data.email
const password = data.password
dispatch(updateUserProfileAction({
‘id’: user._id,
‘name’: name,
’email’: email,
‘password’: password
}))
reset({password: ”, confirmPassword: ”})
setSuccessUpdate(‘Profile Successfully Update’)
}
return (
my profile
{
loading ? :
error ? :
successUpdate ? :
}
FullName
{errors.name?.type === ‘required’ &&
fullName is required}
{errors.name?.type === ‘matches’ &&
fullName not valid}
EmailAddress
{errors.email?.type === ‘required’ &&
email is required}
{errors.email?.type === ‘matches’ &&
Invalid Email Address}
password
{errors.password?.type === ‘required’ &&
{errors.password.message}}
{errors.password?.type === ‘min’ &&
minimum 8 characters}
{errors.password?.type === ‘matches’ &&
password not secure(use @,CL word,)}
Confirm Password
{errors.confirmPassword?.type === ‘required’ &&
{errors.confirmPassword.message}}
{errors.confirmPassword?.type === “oneOf” &&
{errors.confirmPassword.message}}
Update
my orders
);
};
export default ProfileScreen;
ابوالفضل حسن زاده –
سلام و درود بر شما . خیلی ممنون از یادآوری که کردید و افرین به شما که فراتر از پروژه پیش رفتید . انشالله که دیگر فراگیران هم استفاده کنند.
ایمان نم (خریدار محصول) –
استاد عزیز در فصل های این دوره یک چیز به شدت نیاز هست که ممنون میشم به عنوان یک فصل جداگانه این قابلیت رو قرار بدهید. در انتها بی زحمت این پروژه رو PWA اش رو هم پیاده سازی کنید که بسیار لازم و کاربردی هست.
ابوالفضل حسن زاده –
سلام به شما خیلی ممنون از پیشنهاد خوبتون یادداشت کردم که انشالله در آینده بهش بپردازیم.
ایمان (خریدار محصول) –
این فصول باقی مانده رو کی انشا.. انتشار میدید؟ مدرس آقای آسفی هستند یا آقای حسن زاده ؟
ابوالفضل حسن زاده –
سلام . انشالله به زودی منتشر میکنیم، بنده تا اخر این پروژه در خدمت شما هستم.
iman (خریدار محصول) –
با سلام . این دوره فصل دیگری هم دارید یا تمام شد؟
ابوالفضل حسن زاده –
سلام وقت شما بخیر . دو یا سه فصل دیگر باقی مانده . فصل های ثبت سفارش و پرداخت انلاین و …….