Как создать платформу электронной коммерции Web3 с помощью React и Solidity: (ЧАСТЬ II)

Как создать платформу электронной коммерции Web3 с помощью React и Solidity: (ЧАСТЬ II)

27 марта 2022 г.

Что вы будете создавать, см. [живую демонстрацию] (https://fresher-a5113.web.app/) и [репозиторий GitHub] (https://github.com/Daltonic/freshers) для получения дополнительной информации.


Добавить новый продукт


Оплата эфирами


Чат с продавцом


Введение


В ПЕРВОЙ ЧАСТИ этого руководства мы создали смарт-контракт, на котором работает наше приложение. Теперь давайте создадим интерфейс для взаимодействия с ним, как вы можете видеть выше.


Не будем много говорить, давайте займемся кодированием… Начнем с установки остальных зависимостей для этого приложения.


Установка зависимостей приложений


На вашем терминале выполните следующие команды…


пряжа добавить firebase #Database SDK


пряжа добавить @cometchat-pro/chat #Chat SDK


пряжа добавить @material-tailwind/react #UI Kit


Если вы успешно выполнили приведенные выше команды, давайте перейдем к созданию закрытых ключей для Firebase и CometChat.


Создание закрытых ключей


Чтобы использовать Firebase или CometChat SDK, нам нужно создать приложение с их услугами. Не волнуйтесь, это не будет стоить вам ни копейки. Firebase ограничен, но бесплатен, этого более чем достаточно, чтобы помочь вам изучить разработку с полным стеком. CometChat предлагает своим пользователям пробную версию для тестирования своего SDK и ознакомления с тем, как работает их технология.


Создание приложения с помощью Firebase


Используйте этот пример. Если у вас еще нет учетной записи Firebase, создайте ее для себя. После этого перейдите в Firebase и создайте новый проект под названием freshers, затем активируйте службу аутентификации Google, как описано ниже.


Страница проектов Firebase


Шаг 1


Шаг 2


Шаг 3


Firebase поддерживает аутентификацию через различных провайдеров. Например, социальная аутентификация, номера телефонов и традиционный метод электронной почты и пароля. Поскольку в этом руководстве мы будем использовать аутентификацию Google, нам нужно включить ее для проекта, который мы создали в Firebase, поскольку по умолчанию она отключена. Щелкните метод входа на вкладке аутентификации для вашего проекта, и вы должны увидеть список поставщиков, которые в настоящее время поддерживаются Firebase.


Служба аутентификации Firebase


Шаг 1


Шаг 2


Шаг 3


Супер, это все для аутентификации Firebase, давайте сгенерируем ключи конфигурации Firebase SDK.


Вам нужно пойти и зарегистрировать свое приложение в рамках вашего проекта Firebase.


Страница обзора проекта


На странице обзора проекта выберите вариант добавления приложения и выберите web в качестве платформы.


!)


!)


Вернитесь на страницу обзора проекта после завершения регистрации конфигурации SDK, как показано на изображении ниже.


Страница обзора проекта


Теперь вы нажимаете на настройки проекта, чтобы скопировать настройки конфигурации SDK.


Настройки проекта


Ключи конфигурации, показанные на изображении выше, необходимо скопировать в файл .env. Позже мы будем использовать его в этом проекте.


Создайте файл с именем firebase.js в папке src этого проекта и вставьте в него следующие коды перед сохранением.


```javascript


импортировать {initializeApp} из 'firebase/app'


импортировать {setAlert} из './store'


импорт {


получитьАут,


вход с электронной почтой и паролем,


создать пользователя с электронной почтой и паролем,


выход,


onAuthStateChanged,


} из 'firebase/auth'


импорт {


получитьFirestore,


запрос,


получитьДокументы,


обновлениеДок,


коллекция,


коллекцияГруппа,


Сортировать по,


удалитьдок,


добавитьдок,


док,


сетдок,


серверВременная метка,


} из 'firebase/firestore'


константа firebaseConfig = {


APIKey: процесс.env.REACT_APP_FB_AUTH_KEY,


authDomain: 'fresher-a5113.firebaseapp.com',


идентификатор проекта: 'свежее-a5113',


storageBucket: 'fresher-a5113.appspot.com',


идентификатор отправителя сообщений: '443136794867',


идентификатор приложения: process.env.REACT_APP_FB_APP_ID,


константное приложение = initializeApp (firebaseConfig)


константная авторизация = getAuth (приложение)


const db = getFirestore (приложение)


const logInWithEmailAndPassword = async (адрес электронной почты, пароль) => {


пытаться {


return await signInWithEmailAndPassword (авторизация, электронная почта, пароль). затем (


(рез) => рез.пользователь


} поймать (ошибка) {


setAlert (JSON.stringify (ошибка), «красный»)


const registerWithEmailAndPassword = async (


Эл. адрес,


пароль,


полное имя,


Телефон,


учетная запись,


адрес


пытаться {


const res = await createUserWithEmailAndPassword(авторизация, электронная почта, пароль)


постоянный пользователь = res.user


const userDocRef = doc(db, 'users', user.email)


ожидание setDoc(userDocRef, {


uid: user.uid,


полное имя,


Эл. адрес,


Телефон,


учетная запись,


адрес,


вернуть пользователя


} поймать (ошибка) {


setAlert (JSON.stringify (ошибка), «красный»)


константный выход = асинхронный () => {


пытаться {


ожидание выхода (авторизация)


вернуть истину


} поймать (ошибка) {


setAlert (JSON.stringify (ошибка), «красный»)


const addToOrders = async (корзина) => {


пытаться {


постоянный порядок = {


порядок: Math.random().toString(36).substring(2, 9).toUpperCase(),


отметка времени: serverTimestamp(),


тележка,


жду аддок(


коллекция (БД, пользователи/${auth.currentUser.email}, 'заказы'),


заказ


возврат заказа


} поймать (ошибка) {


setAlert (JSON.stringify (ошибка), «красный»)


const addProduct = async (продукт) => {


пытаться {


жду аддок(


коллекция (db, users/${auth.currentUser.email}, 'products'),


имя: product.name,


UID: auth.currentUser.uid,


электронная почта: auth.currentUser.email,


цена: продукт.цена,


описание: описание продукта,


учетная запись: product.account,


imgURL: продукт.imgURL,


запас: ((Math.random() * 10) | 0) + 1,


отметка времени: serverTimestamp(),


} поймать (ошибка) {


setAlert (JSON.stringify (ошибка), «красный»)


const getProducts = асинхронный () => {


пытаться {


константные продукты = запрос (


collectionGroup (дб, «продукты»),


orderBy('отметка времени', 'описание')


const snapshot = ожидание getDocs (продукты)


вернуть snapshot.docs.map((doc) => ({


идентификатор: doc.id,


...док.данные(),


цена: число(doc.data().price),


} поймать (ошибка) {


setAlert (JSON.stringify (ошибка), «красный»)


const getProduct = асинхронный (идентификатор) => {


пытаться {


константные продукты = запрос (


collectionGroup (дб, «продукты»),


orderBy('отметка времени', 'описание')


const snapshot = ожидание getDocs (продукты)


const product = snapshot.docs.find((doc) => doc.id == id)


вернуть {


идентификатор: product.id,


...Данные продукта(),


цена: число (продукт.данные().цена),


} поймать (ошибка) {


setAlert (JSON.stringify (ошибка), «красный»)


const updateProduct = async (продукт) => {


const productRef = doc(db, users/${product.email}/products, product.id)


пытаться {


ждать updateDoc(productRef, продукт)


} поймать (ошибка) {


setAlert (JSON.stringify (ошибка), «красный»)


const deleteProduct = async (продукт) => {


const productRef = doc(db, users/${product.email}/products, product.id)


пытаться {


ожидание удаления документа (productRef)


} поймать (ошибка) {


setAlert (JSON.stringify (ошибка), «красный»)


экспорт {


авторизация,


дБ,


войти с электронной почтой и паролем,


зарегистрироваться с электронной почтой и паролем,


выйти,


onAuthStateChanged,


добавитьПродукт,


добавить в заказы,


получитьПродукты,


получитьПродукт,


обновлениеПродукт,


удалитьПродукт,


Вы молодец, если все правильно сделали. Далее мы сделаем что-то подобное для CometChat.


Создание приложения с CometChat


Перейдите на [CometChat] (https://app.cometchat.com/app/) и зарегистрируйтесь, если у вас нет учетной записи. Затем войдите в систему, и вы увидите экран ниже.


Панель управления CometChat


Используйте это в качестве примера, чтобы создать новое приложение с названием freshers, нажав кнопку Добавить новое приложение. Вам будет представлено модальное окно, где вы можете ввести данные приложения. На изображении ниже показан пример.


Добавить модальное приложение


После создания приложения вы будете перенаправлены на панель инструментов, которая должна выглядеть примерно так.


Ключ API здесь


Ключ REST API здесь


Вы также должны скопировать эти ключи в файл .env.


Наконец, удалите предварительно загруженных пользователей и группы, как показано на изображениях ниже.


Список пользователей


Список групп


Круто, этого будет достаточно для настроек. Используйте этот шаблон, чтобы убедиться, что ваш файл .env соответствует нашему соглашению.


ENDPOINT_URL=


SECRET_KEY=<СЕКРЕТ_ФРАЗА>


DEPLOYER_KEY=<ВАШ_ЧАСТНЫЙ_КЛЮЧ>


REACT_APP_COMET_CHAT_REGION=<ВАШ_COMET_CHAT_REGION>


REACT_APP_COMET_CHAT_APP_ID=


REACT_APP_COMET_CHAT_AUTH_KEY=<ВАШ_COMET_CHAT_AUTH_KEY>


REACT_APP_FB_AUTH_KEY=<ВАШ_FIREBASE_AUTH_KEY>


REACT_APP_FB_APP_ID=<ВАШ_FIREBASE_APP_ID>


Наконец, создайте файл с именем cometChat.js в папке src этого проекта и вставьте в него приведенный ниже код.


```javascript


импортировать {CometChat} из '@cometchat-pro/chat'


const КОНСТАНТЫ = {


APP_ID: process.env.REACT_APP_COMET_CHAT_APP_ID,


РЕГИОН: process.env.REACT_APP_COMET_CHAT_REGION,


Auth_Key: process.env.REACT_APP_COMET_CHAT_AUTH_KEY,


константа initCometChat = асинхронная () => {


пытаться {


постоянный идентификатор приложения = CONSTANTS.APP_ID


константная область = CONSTANTS.REGION


const appSetting = новый CometChat.AppSettingsBuilder()


.subscribePresenceForAllUsers()


.setRegion(регион)


.строить()


await CometChat.init(appID, appSetting).then(() =>


console.log('Инициализация успешно завершена')


} поймать (ошибка) {


console.log(ошибка)


const loginWithCometChat = async (UID) => {


пытаться {


const authKey = CONSTANTS.Auth_Key


await CometChat.login(UID, authKey).then((user) =>


console.log('Вход выполнен успешно:', {пользователь})


} поймать (ошибка) {


console.log(ошибка)


const signInWithCometChat = async (UID, имя) => {


пытаться {


пусть authKey = CONSTANTS.Auth_Key


постоянный пользователь = новый CometChat.User(UID)


user.setName(имя)


return await CometChat.createUser(пользователь, authKey).then((пользователь) => пользователь)


} поймать (ошибка) {


console.log(ошибка)


const logOutWithCometChat = async () => {


пытаться {


await CometChat.logout().then(() => console.log('Выход из системы выполнен успешно'))


} поймать (ошибка) {


console.log(ошибка)


const getMessages = асинхронный (UID) => {


пытаться {


постоянный предел = 30


const messagesRequest = ожидание нового CometChat.MessagesRequestBuilder()


.setUID(UID)


.setLimit(лимит)


.строить()


return await messagesRequest.fetchPrevious().then((сообщения) => сообщения)


} поймать (ошибка) {


console.log(ошибка)


const sendMessage = async (receiverID, messageText) => {


пытаться {


константный приемникType = CometChat.RECEIVER_TYPE.USER


const textMessage = ожидание нового CometChat.TextMessage(


идентификатор получателя,


текст сообщения,


Тип приемника


return await CometChat.sendMessage(textMessage).then((сообщение) => сообщение)


} поймать (ошибка) {


console.log(ошибка)


const getConversations = асинхронный () => {


пытаться {


постоянный предел = 30


константные разговорыRequest = новый CometChat.ConversationsRequestBuilder()


.setLimit(лимит)


.строить()


возврат ожидания разговоровЗапрос


.fetchNext()


.then((список_разговоров) => список_разговоров)


} поймать (ошибка) {


console.log(ошибка)


экспорт {


initCometChat,


логин с CometChat,


знакInWithCometChat,


logOutWithCometChat,


получить сообщения,


Отправить сообщение,


получитьразговоры,


Круто, давайте приступим к интеграции их всех в наше приложение, начнем мы с компонентов.


Сборка компонентов


Давайте начнем создавать все компоненты один за другим, всегда обращайтесь к git repo, если у вас возникнут какие-либо проблемы.


Регистрационный компонент


Зарегистрировать компонент


Этот компонент отвечает за сохранение новых пользователей в Firebase. Перейдите к компонентам src >> и создайте файл с именем Register.jsx.


```javascript


импортировать {useState} из «реагировать»


импортировать кнопку из '@material-tailwind/react/Button'


импортировать {Link, useNavigate} из 'react-router-dom'


импорт {registerWithEmailAndPassword, выход} из '../firebase'


импортировать {signInWithCometChat} из '../cometChat'


импортировать {setAlert} из '../store'


константный регистр = () => {


const [полное имя, setFullname] = useState ('')


const [электронная почта, setEmail] = useState('')


const [пароль, setPassword] = useState('')


const [телефон, setPhone] = useState('')


const [адрес, setAddress] = useState ('')


const [учетная запись, setAccount] = useState ('')


константная навигация = useNavigate()


const handleRegister = async (e) => {


e.preventDefault()


если (


электронная почта == '' ||


пароль == '' ||


полное имя == '' ||


телефон == '' ||


счет == '' ||


адрес == ''


вернуть


Зарегистрируйтесь с электронной почтой и паролем (


Эл. адрес,


пароль,


полное имя,


Телефон,


учетная запись,


адрес


).then((пользователь) => {


если (пользователь) {


выход из системы (). затем (() => {


signInWithCometChat(user.uid, полное имя).then(() => {


Сброс форма()


setAlert('Регистрация прошла успешно')


навигация('/вход')


константа resetForm = () => {


установитьПолное имя('')


установить электронную почту ('')


Установка пароля('')


установить телефон ('')


установить учетную запись ('')


установитьАдрес('')


вернуть (




<форма


onSubmit={handleRegister}


className="относительный flex w-полный flex-wrap items-stretch w-96 px-8"



<ввод


тип = "текст"


className="px-3 py-3 заполнитель-blueGray-300 text-blueGray-600 относительный bg-white bg-white закругленный текст-sm граница border-blueGray-300 контур-нет фокус: контур-нет фокус: кольцо w-полный пл-10"


заполнитель = "Полное имя"


значение = {полное имя}


onChange={(e) => setFullname(e.target.value)}


требуется




<ввод


тип = "электронная почта"


className="px-3 py-3 заполнитель-blueGray-300 text-blueGray-600 относительный bg-white bg-white закругленный текст-sm граница border-blueGray-300 контур-нет фокус: контур-нет фокус: кольцо w-полный пл-10"


заполнитель = "Электронная почта"


значение = {электронная почта}


onChange={(e) => setEmail(e.target.value)}


требуется




<ввод


тип = "пароль"


className="px-3 py-3 заполнитель-blueGray-300 text-blueGray-600 относительный bg-white bg-white закругленный текст-sm граница border-blueGray-300 контур-нет фокус: контур-нет фокус: кольцо w-полный пл-10"


заполнитель = "**"


значение = {пароль}


onChange={(e) => setPassword(e.target.value)}


требуется




<ввод


тип = "число"


className="px-3 py-3 заполнитель-blueGray-300 text-blueGray-600 относительный bg-white bg-white закругленный текст-sm граница border-blueGray-300 контур-нет фокус: контур-нет фокус: кольцо w-полный пл-10"


заполнитель = "081 056 8262"


значение = {телефон}


onChange={(e) => setPhone(e.target.value)}


требуется




<ввод


тип = "текст"


className="px-3 py-3 заполнитель-blueGray-300 text-blueGray-600 относительный bg-white bg-white закругленный текст-sm граница border-blueGray-300 контур-нет фокус: контур-нет фокус: кольцо w-полный пл-10"


placeholder="Адрес кошелька"


значение = {аккаунт}


onChange={(e) => setAccount(e.target.value)}


требуется




<ввод


тип = "текст"


className="px-3 py-3 заполнитель-blueGray-300 text-blueGray-600 относительный bg-white bg-white закругленный текст-sm граница border-blueGray-300 контур-нет фокус: контур-нет фокус: кольцо w-полный пл-10"


заполнитель = "Адрес"


значение = {адрес}


onChange={(e) => setAddress(e.target.value)}


требуется





Уже участник? войти







экспорт по умолчанию Регистрация


Потрясающий!!!


Компонент входа


Компонент входа


Давайте также создадим еще один компонент с именем Login.jsx в папке src >> components и вставим в него приведенный ниже код.


```javascript


импортировать {useState} из «реагировать»


импортировать {Link, useNavigate} из 'react-router-dom'


импортировать {logInWithEmailAndPassword} из '../firebase'


импортировать {loginWithCometChat} из '../cometChat'


импортировать {setAlert} из '../store'


импортировать кнопку из '@material-tailwind/react/Button'


постоянный Логин = () => {


const [электронная почта, setEmail] = useState('')


const [пароль, setPassword] = useState('')


константная навигация = useNavigate()


const handleLogin = async (e) => {


e.preventDefault()


если (электронная почта == '' || пароль == '') вернуть


logInWithEmailAndPassword(email, password).then((user) => {


если (пользователь) {


loginWithCometChat(user.uid).then(() => {


Сброс форма()


setAlert('Вход выполнен успешно')


навигация('/')


константа resetForm = () => {


установить электронную почту ('')


Установка пароля('')


вернуть (




<форма


onSubmit={handleLogin}


className="относительный flex w-полный flex-wrap items-stretch w-96 px-8"


Войти



<ввод


тип = "электронная почта"


className="px-3 py-3 заполнитель-blueGray-300 text-blueGray-600 относительный bg-white bg-white закругленный текст-sm граница border-blueGray-300 контур-нет фокус: контур-нет фокус: кольцо w-полный пл-10"


заполнитель = "Электронная почта"


значение = {электронная почта}


onChange={(e) => setEmail(e.target.value)}


требуется




<ввод


тип = "пароль"


className="px-3 py-3 заполнитель-blueGray-300 text-blueGray-600 относительный bg-white bg-white закругленный текст-sm граница border-blueGray-300 контур-нет фокус: контур-нет фокус: кольцо w-полный пл-10"


заполнитель = "**"


значение = {пароль}


onChange={(e) => setPassword(e.target.value)}


требуется





Регистрация нового пользователя







экспорт по умолчанию Логин


Круто, эти два компонента составляют аспект аутентификации этого приложения. Позже мы объединим их в соответствующие представления.


Компонент заголовка


Компонент заголовка


Этот компонент инкапсулирует страницы нашего приложения. Он был создан с помощью бесплатного набора Creative TIm Tailwind-Material UI Kit. Создайте файл с именем Header.jsx в каталоге src >> component и вставьте в него приведенные ниже коды.


```javascript


импортировать {useState} из «реагировать»


импортировать {Link, useNavigate} из 'react-router-dom'


импортировать {setAlert, useGlobalState} из '../store'


импортировать {выход} из '../firebase'


импортировать {logOutWithCometChat} из '../cometChat'


импортировать {connectWallet} из '../shared/Freshers'


импортировать панель навигации из '@material-tailwind/react/Navbar'


импортировать NavbarContainer из '@material-tailwind/react/NavbarContainer'


импортировать NavbarWrapper из '@material-tailwind/react/NavbarWrapper'


импортировать NavbarBrand из '@material-tailwind/react/NavbarBrand'


импортировать NavbarToggler из '@material-tailwind/react/NavbarToggler'


импортировать NavbarCollapse из '@material-tailwind/react/NavbarCollapse'


импортировать Nav из '@material-tailwind/react/Nav'


импортировать NavItem из '@material-tailwind/react/NavItem'


константный заголовок = () => {


const [openNavbar, setOpenNavbar] = useState (ложь)


const [корзина] = useGlobalState('корзина')


const [isLoggedIn] = useGlobalState('isLoggedIn')


const [connectedAccount] = useGlobalState('connectedAccount')


константная навигация = useNavigate()


константа handleSignOut = () => {


выход().затем((рез) => {


если (рез) {


logOutWithCometChat().then(() => {


setAlert('Выход из системы выполнен успешно')


навигация('/вход')


вернуть (





<Ссылка на ="/">


Первокурсники



<NavbarToggler


цвет = "белый"


onClick={() => setOpenNavbar(!openNavbar)}


рябь = "белый"




{Вошел в систему? (


<Навигация слева>



клиенты




Добавить продукт




<Навигация справа>


{Вошел в систему? (


{подключенная учетная запись? нулевой : (


<NavItem


onClick={connectWallet}


активный = "свет"


рябь = "свет"


Подключить кошелек




Выйти





Авторизоваться





Корзина {cart.length}







экспорт заголовка по умолчанию


Пищевой компонент


Этот компонент визуализирует определенные свойства продуктов питания, чтобы отображать их в красиво оформленной карточке с помощью CSS Tailwind и дизайна материалов. Создайте файл с именем Food.jsx в папке компонентов и вставьте в него следующие коды.



Каждая карточка отображает название, изображение, описание, цену и остатки продуктов питания. Вот код для него.


```javascript


импортировать React из «реагировать»


импортировать карту из '@material-tailwind/react/Card'


импортировать CardImage из '@material-tailwind/react/CardImage'


импортировать CardBody из '@material-tailwind/react/CardBody'


импортировать CardFooter из '@material-tailwind/react/CardFooter'


импортировать H6 из '@material-tailwind/react/Heading6'


импортировать абзац из '@material-tailwind/реагировать/абзац'


импортировать кнопку из '@material-tailwind/react/Button'


импортировать {setAlert, setGlobalState, useGlobalState} из '../store'


импортировать {Link} из 'react-router-dom'


const Food = ({item}) => {


const [корзина] = useGlobalState('корзина')


const addToCart = (элемент) => {


элемент.добавлено = правда


пусть cartItems = [...корзина]


const newItem = { ...item, qty: (item.qty += 1), stock: (item.stock -= 1) }


если (cart.find((_item) => _item.id == item.id)) {


cartItems[item] = новыйItem


setGlobalState('корзина', [...cartItems])


} еще {


setGlobalState('корзина', [...cartItems, newItem])


setAlert(${item.name} добавлено в корзину!)


const toCurrency = (число) =>


num.toLocaleString('en-US', {


стиль: 'валюта',


валюта: 'доллар США',


вернуть (



<Карта>


/product/ + item.id}>




<Карточка>


/product/ + item.id}>


{item.name}


<Цвет абзаца="серый">


Не бойтесь правды, потому что нам нужно...



<дел


цвет = "черный"


className="flex flex-row justify-between items-center"



{toCurrency (цена товара)}



{item.stock} в наличии





{item.stock > 0 ? (


<Кнопка


onClick={() => addToCart(элемент)}


цвет = "зеленый"


размер = "мд"


рябь = "свет"


отключено={item.stock == 0}


Добавить в корзину



<Кнопка


цвет = "зеленый"


размер = "мд"


тип кнопки = "контур"


рябь = "свет"


инвалид


Нет на складе






экспортировать еду по умолчанию


Далее, давайте посмотрим на пищевой компонент.


Пищевые компоненты


Этот компонент отвечает за отображение всей коллекции данных о продуктах питания в нашей базе данных. Давайте посмотрим на его фрагмент кода.


Компонент продуктов питания


Тем не менее, в каталоге компонентов создайте еще один файл с именем Foods.jsx и вставьте в него приведенные ниже коды.


```javascript


импортировать еду из './Food'


const Продукты = ({ продукты }) => {


вернуть (



{products.map((item, i) => (


<Продукт питания={item} key={i} />



экспорт продуктов по умолчанию


Наконец, давайте посмотрим на компонент CartItem.


Компонент CartItem


Компонент CartItem


Этот компонент отвечает за отображение одного элемента в нашей коллекции корзины. Вот код, отвечающий за это.


```javascript


импортировать {useState} из «реагировать»


импортировать карту из '@material-tailwind/react/Card'


импортировать CardStatusFooter из '@material-tailwind/react/CardStatusFooter'


импортировать {Link} из 'react-router-dom'


импортировать {изображение, кнопку} из '@material-tailwind/реагировать'


импортировать {setGlobalState, useGlobalState} из '../store'


const CartItem = ({ элемент }) => {


const [кол-во, setQty] = useState (item.qty)


const [корзина] = useGlobalState('корзина')


const toCurrency = (число) =>


num.toLocaleString('en-US', {


стиль: 'валюта',


валюта: 'доллар США',


константное увеличениеQty = () => {


пусть cartItems = [...корзина]


const newItem = { ...item, qty: (item.qty += 1), stock: (item.stock -= 1) }


cartItems[item] = новыйItem


setGlobalState('корзина', cartItems)


setQty (новый элемент. количество)


константное уменьшениеQty = () => {


пусть cartItems = [...корзина]


если (кол-во == 1) {


константный индекс = cartItems.indexOf (элемент)


cartItems.splice (индекс, 1)


} еще {


константа newItem = {


...пункт,


кол-во: (шт.кол-во -= 1),


сток: (арт.сток += 1),


cartItems[item] = новыйItem


setQty (новый элемент. количество)


setGlobalState('корзина', cartItems)


вернуть (



<Ссылка


to={'/product/' + item.id}


className="h-12 w-12 объект-содержат MR-4"


<Изображение


источник={item.imgURL}


alt={item.name}


округлено={ложь}


поднял = {правда}



<CardStatusFooter


цвет = "зеленый"


сумма={toCurrency(item.price)}


дата = {item.name}



<Кнопка


цвет = "зеленый"


тип кнопки = "заполнено"


размер = "см"


округлено={ложь}


блок = {ложь}


iconOnly={ложь}


рябь = "темный"


onClick={уменьшениеQty}



{количество}


<Кнопка


цвет = "зеленый"


тип кнопки = "заполнено"


размер = "см"


округлено={ложь}


блок = {ложь}


iconOnly={ложь}


рябь = "темный"


onClick={увеличениеQty}


отключено={item.stock == 0}






Итого: {toCurrency(item.price * qty)}




экспортировать CarItem по умолчанию


Поздравляем, вы только что закончили программировать компоненты, давайте перейдем к созданию представлений…


Виды


Теперь, когда мы создали компоненты, поддерживающие различные представления, давайте приступим к созданию отдельных страниц.


Главный вид


Главный вид


Этот вид визуализирует структуру компонента Food. То есть домашний вид извлекает всю коллекцию продуктов из firebase и показывает их на экране. Давайте посмотрим на коды, отвечающие за это.


Перейдите в каталог представлений и создайте файл с именем Home.jsx, затем вставьте в него приведенный ниже код. На самом деле все эти файлы вы будете создавать в папке views.


```javascript


импортировать {useEffect, useState} из «реагировать»


импортировать заголовок из «../components/Header»


импортировать продукты из «../components/Foods»


импортировать {getProducts} из '../firebase'


const Главная = () => {


const [продукты, setProducts] = useState([])


использоватьЭффект(() => {


getProducts().then((products) => {


products.filter((item) => {


item.price = Число(item.price)


товар.кол-во = 0


setProducts(продукты)


вернуть (



<Заголовок/>


<Продукты питания={продукты} />



экспорт по умолчанию Главная


Вид продукта


Вид продукта


Это представление отвечает за детальное отображение информации о продукте. На этой странице пользователи могут просматривать, редактировать и удалять продукты, а также общаться с продавцом или быстро покупать продукты питания с помощью Ethereum.


Вот код для него…


```javascript


импортировать заголовок из «../components/Header»


импортировать {useEffect, useState} из «реагировать»


импортировать {useParams, useNavigate} из 'react-router-dom'


импортировать {Button, CardImage} из '@material-tailwind/реагировать'


импортировать {getProduct, deleteProduct, auth} из '../firebase'


импортировать {setGlobalState, useGlobalState, setAlert} из '../store'


импортировать {payWithEthers} из '../shared/Freshers'


константа Продукт = () => {


const {идентификатор} = useParams ()


константная навигация = useNavigate()


const [продукт, setProduct] = useState (ноль)


const [корзина] = useGlobalState('корзина')


const [isLoggedIn] = useGlobalState('isLoggedIn')


const [покупатель] = useGlobalState('connectedAccount')


const [ethToUsd] = useGlobalState('ethToUsd')


константа addToCart = () => {


постоянный элемент = продукт


элемент.добавлено = правда


пусть cartItems = [...корзина]


const newItem = { ...item, qty: (item.qty += 1), stock: (item.stock -= 1) }


если (cart.find((_item) => _item.id == item.id)) {


cartItems[item] = новыйItem


setGlobalState('корзина', [...cartItems])


} еще {


setGlobalState('корзина', [...cartItems, newItem])


setAlert('Товар добавлен в корзину')


const handlePayWithEthers = () => {


const item = {...товар, покупатель, цена: (product.price / ethToUsd).toFixed(4) }


payWithEthers(item).then((res) => {


if (res) setAlert('Товар куплен!')


const handleDeleteProduct = () => {


удалитьПродукт(продукт).затем(() => {


setAlert('Товар удален!')


навигация('/')


const toCurrency = (число) =>


num.toLocaleString('en-US', {


стиль: 'валюта',


валюта: 'доллар США',


использоватьЭффект(() => {


getProduct(id).then((data) => setProduct({...data, qty: 1 }))


}, [я бы])


вернуть (



<Заголовок/>


{!!товар ? (







<дел>



{наименование товара}



Информация о продукте




{toCurrency(product.price)}




{product.stock} осталось в наличии





{product.description}





<Кнопка


onClick={добавить в корзину}


цвет = "зеленый"


размер = "мд"


рябь = "свет"


Добавить в корзину



{Вошел в систему? (


{auth.currentUser.uid != product.uid &&


product.account != покупатель ? (


<Кнопка


onClick={handlePayWithEthers}


цвет = "янтарный"


размер = "мд"


рябь = "свет"


Купить с ETH



) : нулевой}


{auth.currentUser.uid == product.uid ? нулевой : (


<Кнопка


onClick={() => navigation('/chat/' + product.uid)}


тип кнопки = "ссылка"


цвет = "зеленый"


размер = "мд"


рябь = "свет"


Чат с продавцом



) : нулевой}


{isLoggedIn && auth.currentUser.uid == product.uid ? (


<Кнопка


onClick={() => navigation('/product/edit/' + id)}


тип кнопки = "ссылка"


цвет = "зеленый"


размер = "мд"


рябь = "свет"


Редактировать продукт



<Кнопка


onClick={handleDeleteProduct}


тип кнопки = "ссылка"


цвет = "красный"


размер = "мд"


рябь = "свет"


Удалить



) : нулевой}





) : нулевой}



экспорт продукта по умолчанию


Вид «Добавить продукт»


!)


Как следует из названия, это представление отвечает за хранение новых продуктов питания в нашей коллекции Firestore. Обратите внимание на фрагмент кода ниже…


```javascript


импортировать {useState} из «реагировать»


импортировать {Link, useNavigate} из 'react-router-dom'


импортировать {addProduct} из '../firebase'


импортировать {setAlert} из '../store'


импортировать {useGlobalState} из '../store'


импортировать кнопку из '@material-tailwind/react/Button'


импортировать заголовок из «../components/Header»


константа AddProduct = () => {


const [имя, setName] = useState('')


const [цена, setPrice] = useState('')


const [imgURL, setImgURL] = useState('')


const [описание, setDescription] = useState('')


const [учетная запись] = useGlobalState («подключенная учетная запись»)


константная навигация = useNavigate()


const handleAddProduct = (e) => {


e.preventDefault()


если (!аккаунт) {


setAlert('Пожалуйста, подключите свою учетную запись метамаски!', 'красный')


вернуть


если (имя == '' || цена == '' || imgURL == '' || описание == '') вернуть


addProduct({ название, цена, imgURL, описание, учетная запись }).then(() => {


setAlert('Продукт успешно создан')


навигация('/')


вернуть (



<Заголовок/>




<форма


onSubmit={handleAddProduct}


className="относительный flex w-полный flex-wrap items-stretch w-96 px-8"


Добавить продукт



<ввод


тип = "текст"


className="px-3 py-3 заполнитель-blueGray-300 text-blueGray-600 относительный bg-white bg-white закругленный текст-sm граница border-blueGray-300 контур-нет фокус: контур-нет фокус: кольцо w-полный пл-10"


заполнитель = "Название продукта"


значение = {имя}


onChange={(e) => setName(e.target.value)}


требуется




<ввод


тип = "число"


мин={1}


шаг={0,01}


className="px-3 py-3 заполнитель-blueGray-300 text-blueGray-600 относительный bg-white bg-white закругленный текст-sm граница border-blueGray-300 контур-нет фокус: контур-нет фокус: кольцо w-полный пл-10"


placeholder="Цена товара"


значение = {цена}


onChange={(e) => setPrice(e.target.value)}


требуется




<ввод


тип = "ссылка"


className="px-3 py-3 заполнитель-blueGray-300 text-blueGray-600 относительный bg-white bg-white закругленный текст-sm граница border-blueGray-300 контур-нет фокус: контур-нет фокус: кольцо w-полный пл-10"


placeholder="URL-адрес изображения продукта"


значение={imgURL}


onChange={(e) => setImgURL(e.target.value)}


требуется




<ввод


тип = "текст"


className="px-3 py-3 заполнитель-blueGray-300 text-blueGray-600 относительный bg-white bg-white закругленный текст-sm граница border-blueGray-300 контур-нет фокус: контур-нет фокус: кольцо w-полный пл-10"


placeholder="Описание продукта"


значение = {описание}


onChange={(e) => setDescription(e.target.value)}


требуется





Вернуться домой








экспорт по умолчанию AddProduct


Круто, мы движемся вперед, давайте посмотрим, как изменить вид продукта…


Вид редактирования продукта


Редактировать продукт


Этот вид позволяет нам редактировать наши существующие продукты питания. Конечно, вы должны быть тем, кто изначально добавил продукт питания в магазин, прежде чем вы сможете редактировать. Редактировать могут только владельцы продукта, давайте посмотрим на коды, выполняющие это действие.


```javascript


импортировать заголовок из «../components/Header»


импортировать кнопку из '@material-tailwind/react/Button'


импортировать {useEffect, useState} из «реагировать»


импортировать {Link, useParams, useNavigate} из 'react-router-dom'


импортировать {updateProduct, getProduct, auth} из '../firebase'


импортировать {setAlert} из '../store'


импортировать {useGlobalState} из '../store'


константа EditProduct = () => {


const {идентификатор} = useParams ()


константная навигация = useNavigate()


const [продукт, setProduct] = useState (ноль)


const [имя, setName] = useState('')


const [цена, setPrice] = useState('')


const [imgURL, setImgURL] = useState('')


const [описание, setDescription] = useState('')


const [учетная запись] = useGlobalState («подключенная учетная запись»)


использоватьЭффект(() => {


getProduct(id).then((данные) => {


если (auth.currentUser.uid != data.uid) перейти('/')


setProduct (данные)


setName(данные.имя)


setPrice (Число (данные. Цена))


setImgURL(данные.imgURL)


setDescription (данные.описание)


}, [я бы])


const handleProductUpdate = (e) => {


e.preventDefault()


если (!аккаунт) {


setAlert('Пожалуйста, подключите свою учетную запись метамаски!', 'красный')


вернуть


если (имя == '' || цена == '' || imgURL == '' || описание == '') вернуть


обновить продукт ({


...товар,


имя,


цена,


imgURL,


описание,


учетная запись,


}).тог(() => {


setAlert('Продукт успешно обновлен')


перейти('/продукт/' + product.id)


вернуть (



<Заголовок/>




<форма


onSubmit={handleProductUpdate}


className="относительный flex w-полный flex-wrap items-stretch w-96 px-8"


Обновить продукт



<ввод


тип = "текст"


className="px-3 py-3 заполнитель-blueGray-300 text-blueGray-600 относительный bg-white bg-white закругленный текст-sm граница border-blueGray-300 контур-нет фокус: контур-нет фокус: кольцо w-полный пл-10"


заполнитель = "Название продукта"


значение = {имя}


onChange={(e) => setName(e.target.value)}


требуется




<ввод


тип = "число"


мин={1}


шаг={0,01}


className="px-3 py-3 заполнитель-blueGray-300 text-blueGray-600 относительный bg-white bg-white закругленный текст-sm граница border-blueGray-300 контур-нет фокус: контур-нет фокус: кольцо w-полный пл-10"


placeholder="Цена товара"


значение = {цена}


onChange={(e) => setPrice(e.target.value)}


требуется




<ввод


тип = "ссылка"


className="px-3 py-3 заполнитель-blueGray-300 text-blueGray-600 относительный bg-white bg-white закругленный текст-sm граница border-blueGray-300 контур-нет фокус: контур-нет фокус: кольцо w-полный пл-10"


placeholder="URL-адрес изображения продукта"


значение={imgURL}


onChange={(e) => setImgURL(e.target.value)}


требуется




<ввод


тип = "текст"


className="px-3 py-3 заполнитель-blueGray-300 text-blueGray-600 относительный bg-white bg-white закругленный текст-sm граница border-blueGray-300 контур-нет фокус: контур-нет фокус: кольцо w-полный пл-10"


placeholder="Описание продукта"


значение = {описание}


onChange={(e) => setDescription(e.target.value)}


требуется




/product/ + id}>


Назад к продукту








экспортировать по умолчанию EditProduct


Наконец, для случаев, связанных с продуктами, давайте посмотрим на вид корзины…


Вид корзины


Вид корзины


В этом представлении вы можете изменять и размещать свои заказы. Как только вы размещаете свой заказ, он сразу же сохраняется в Firestore. Ниже показано, как написан код.


```javascript


импортировать CartItem из '../components/CartItem'


импортировать заголовок из «../components/Header»


импортировать {Link} из 'react-router-dom'


импортировать {кнопку} из '@material-tailwind/реагировать'


импортировать {useEffect, useState} из «реагировать»


импортировать {addToOrders} из '../firebase'


импортировать {setAlert, setGlobalState, useGlobalState} из '../store'


const Корзина = () => {


const [корзина] = useGlobalState('корзина')


const [isLoggedIn] = useGlobalState('isLoggedIn')


const [всего, setTotal] = useState (0)


константа getTotal = () => {


пусть сумма = 0


cart.forEach((товар) => (всего += товар.кол-во * товар.цена))


setTotal (всего)


const placeOrder = () => {


если (!isLoggedIn) вернуть


addToOrders(корзина).then((данные) => {


setGlobalState('корзина', [])


setAlert(Заказ размещен с идентификатором: ${data.order})


const clearCart = () => {


setGlobalState('корзина', [])


const toCurrency = (число) =>


num.toLocaleString('en-US', {


стиль: 'валюта',


валюта: 'доллар США',


useEffect(() => getTotal(), [корзина])


вернуть (



<Заголовок/>



{корзина.длина > 0? (





{cart.map((элемент, я) => (






Общая сумма:



{в валюте (всего)}





<Кнопка


onClick={clearCart}


цвет = "красный"


рябь = "свет"


тип = "отправить"


Очистить корзину



{Вошел в систему? (


<Кнопка


onClick={placeOrder}


цвет = "зеленый"


рябь = "свет"


тип = "отправить"


Разместить заказ



) : нулевой}





Корзина пуста, добавьте несколько товаров в корзину



Выберите продукт






экспорт корзины по умолчанию


Далее, давайте позаботимся о последних четырех представлениях в нашем трее…


Просмотр списка чатов


Вид списка чатов


В этом представлении просто перечислены недавние разговоры с вашими клиентами. Это возможно с помощью CometChat SDK, приведенные ниже коды показывают, как это было реализовано.


```javascript


импортировать заголовок из «../components/Header»


импортировать {getConversations} из '../cometChat'


импортировать {useEffect, useState} из «реагировать»


импортировать {Link} из 'react-router-dom'


импортировать {auth} из '../firebase'


const ChatList = () => {


const [клиенты, setCustomers] = useState([])


const [загружено, setLoaded] = useState (false)


использоватьЭффект(() => {


getConversations().then((разговор) => {


console.log(разговор)


setCustomers(разговор)


setLoaded (истина)


вернуть (



<Заголовок/>






Последние чаты



{загружено


? customers.map((клиент, я) => (


<Разговор


ключ = {я}


currentUser={auth.currentUser.uid.toLowerCase()}


владелец = {customer.lastMessage.receiverId.toLowerCase()}


разговор={customer.lastMessage}


: нулевой}






const Conversation = ({ беседа, текущий пользователь, владелец }) => {


постоянный владелец = (ключ) => {


вернуть currentUser == владелец


? разговор. отправитель [ключ]


: разговор.приемник[ключ]


const timeAgo = (дата) => {


пусть секунды = Math.floor((новая дата() - дата) / 1000)


пусть интервал = секунды / 31536000


если (интервал > 1) {


вернуть Math.floor(интервал) + 'год'


интервал = секунды / 2592000


если (интервал > 1) {


return Math.floor(интервал) + 'mo'


интервал = секунды / 86400


если (интервал > 1) {


вернуть Math.floor(интервал) + 'd'


интервал = секунды / 3600


если (интервал > 1) {


вернуть Math.floor(интервал) + 'ч'


интервал = секунды / 60


если (интервал > 1) {


вернуть Math.floor(интервал) + 'm'


вернуть Math.floor (секунды) + 's'


вернуть (


<Ссылка


to={'/chat/' + владелец('uid')}


className="flex flex-row justify-between items-center


mb-2 py-2 px-4 bg-grey-100 rounded-lg курсор-указатель"



{владелец('имя')}


{беседа.текст}




{timeAgo(новая дата(число(диалог.sentAt) * 1000).getTime())}




экспортировать список чатов по умолчанию


Просмотр чата


Вид чата


Это вид чата один на один для общения продавца и покупателя. CometChat SDK упрощает эту задачу. Следующий код демонстрирует, как это работает довольно хорошо.


```javascript


импортировать {CometChat} из '@cometchat-pro/chat'


импортировать {sendMessage, getMessages} из '../cometChat'


импортировать {useEffect, useState} из «реагировать»


импортировать {useParams} из 'react-router-dom'


импортировать заголовок из «../components/Header»


постоянный чат = () => {


const {идентификатор получателя} = useParams()


const [сообщение, setMessage] = useState('')


const [сообщения, setMessages] = useState([])


константа handleSendMsg = (e) => {


e.preventDefault()


sendMessage(ID получателя, сообщение).then((msg) => {


setMessages((prevState) => [...prevState, msg])


установитьсообщение('')


прокрутить до конца ()


константа handleGetMessages = () => {


getMessages(receiverID).then((msgs) => {


setMessages (сообщения)


прокрутить до конца ()


const listenForMessage = (listenerID) => {


CometChat.addMessageListener(


идентификатор слушателя,


новый CometChat.MessageListener({


onTextMessageReceived: (сообщение) => {


setMessages((prevState) => [...prevState, сообщение])


прокрутить до конца ()


константа scrollToEnd = () => {


const elmnt = document.getElementById('контейнер сообщений')


elmnt.scrollTop = elmnt.scrollHeight


использоватьЭффект(() => {


обрабатыватьGetMessages()


слушатьForMessage (идентификатор получателя)


}, [идентификатор получателя])


вернуть (



<Заголовок/>






Чат



<дел


id="контейнер сообщений"


className="относительный p-6 flex-auto h-64 overflow-y-scroll"


стиль={{ высота: '20rem' }}



{messages.map((msg, я) =>


msg?.receiverId?.toLowerCase() != приемникID.toLowerCase() ? (


<дел


ключ = {я}


className="flex flex-col justify-center items-start w-full mb-4"



{msg.text}




<дел


ключ = {я}


className="flex flex-col justify-center items-end w-full mb-4"



{msg.text}






<форма


onSubmit={handleSendMsg}


className="flex flex-row justify-center items-center mt-4 py-4"


<ввод


тип = "текст"


placeholder="Введите сообщение..."


className="px-3 py-8 заполнитель-blueGray-300 text-blueGray-600 относительный


bg-green-100 закругленный текст-sm граница border-blueGray-300


контур-нет фокус: контур-нет фокус: кольцо w-полный изгиб-1 граница-0"


значение = {сообщение}


onChange={(e) => setMessage(e.target.value)}







экспортировать чат по умолчанию


Регистрация


Создайте новый файл с именем SignUp.jsx и вставьте в него приведенные ниже коды.


```javascript


импортировать заголовок из «../components/Header»


импортировать регистр из «../components/Register»


константа SignUp = () => {


вернуть (



<Заголовок/>


<Регистрация />



экспортировать регистрацию по умолчанию


Вид входа


Давайте сделаем то же самое для представления SignIn, создадим новый файл с именем SignIn.jsx и вставим в него приведенные ниже коды.


```javascript


импортировать заголовок из «../components/Header»


импортировать логин из '../components/Login'


const SignIn = () => {


вернуть (



<Заголовок/>


<Вход />



экспортировать вход по умолчанию


Удивительно, мы только что добавили все необходимые представления в наше приложение, давайте приведем в порядок остальную часть кода…


Файл App.jsx


Это первый файл, который запускается перед каждым другим представлением и компонентом в нашем приложении. Вставьте в файл App.jsx следующие коды.


```javascript


импортировать {useEffect, useState} из «реагировать»


импортировать {Routes, Route} из 'react-router-dom'


импортировать {useGlobalState, setGlobalState, lastPrice} из './store'


импортировать {auth, onAuthStateChanged} из './firebase'


импортировать продукт из './views/Product'


импортировать Home из './views/Home'


импортировать SignUp из './views/SignUp'


импортировать SignIn из './views/SignIn'


импортировать AuthGuard из './AuthGuard'


импортировать EditProduct из './views/EditProduct'


импортировать AddProduct из './views/AddProduct'


импортировать корзину из './views/Cart'


импортировать чат из './views/Chat'


импортировать ChatList из './views/ChatList'


импортировать { loadWeb3 } из './shared/Freshers'


приложение функции () {


const [пользователь, setUser] = useState (ноль)


const [isLoaded, setIsLoaded] = useState (false)


const [предупреждение] = useGlobalState («предупреждение»)


использоватьЭффект(() => {


loadWeb3()


onAuthStateChanged(авторизация, (пользователь) => {


если (пользователь) {


setUser(пользователь)


setGlobalState('isLoggedIn', правда)


} еще {


установитьПользователя (ноль)


setGlobalState('isLoggedIn', ложь)


setIsLoaded (истина)


последняяЦена()


вернуть (



{Загружен? (


{предупреждение.показать? (


<дел


className={text-white px-6 py-2 border-0 округленный относительный bg-${alert.color}-500}






Внимание! {alert.msg}!



<кнопка


onClick={() =>


setGlobalState('предупреждение', {показать: false, сообщение: ''})


className="абсолютный bg-прозрачный текст-2xl шрифт-полужирный ведущий-нет справа-0 верхний-0 mt-2 mr-6 контур-нет фокус: контур-нет"


×




) : нулевой}


<Маршруты>


} />


} />


<Маршрут


путь = "продукт/редактировать/:идентификатор"


элемент={


<Пользователь AuthGuard={пользователь}>


<РедактироватьПродукт/>



<Маршрут


путь="продукт/добавить"


элемент={


<Пользователь AuthGuard={пользователь}>


<ДобавитьПродукт/>



<Маршрут


путь = "чат /: идентификатор получателя"


элемент={


<Пользователь AuthGuard={пользователь}>


<Чат />



<Маршрут


путь = "клиенты"


элемент={


<Пользователь AuthGuard={пользователь}>


<Список чатов />



} />


} />


} />



) : нулевой}



экспортировать приложение по умолчанию


Файл AuthGuard.jsx


Этот файл содержит логику для предотвращения доступа неаутентифицированных пользователей к защищенным маршрутам в нашем приложении. Создайте новый файл в папке src и назовите его AuthGuard.jsx, затем вставьте в него следующие коды.


```javascript


импортировать {Navigate} из 'react-router-dom'


const AuthGuard = ({ пользователь, дети, redirectPath = '/signin' }) => {


если (!пользователь) {


return <Перейти к={redirectPath} заменить />


вернуть детей


экспортировать AuthGuard по умолчанию


Файл Index.jsx


Вставьте следующие коды в файл index.jsx и сохраните…


```javascript


импортировать React из «реагировать»


импортировать ReactDOM из 'react-dom'


импортировать {BrowserRouter} из 'react-router-dom'


импортировать '@material-tailwind/реагировать/tailwind.css'


импортировать {initCometChat} из './cometChat'


импортировать приложение из './App'


initCometChat().then(() => {


ReactDOM.render(


<Браузермаршрутизатор>


<Приложение />


,


document.getElementById('корень')


Магазин


Используя мощь библиотеки react-hooks-global-state, давайте создадим хранилище для управления некоторыми из наших глобальных переменных состояния. В каталоге src, >> store создайте файл с именем index.jsx и вставьте в него приведенные ниже коды.


```javascript


импорт { createGlobalState } из 'реагировать-хуки-глобальное-состояние'


const { setGlobalState, useGlobalState } = createGlobalState ({


isLoggedIn: ложь,


предупреждение: {показать: ложь, сообщение: '', цвет: ''},


корзина: [],


контракт: нулевой,


подключенный аккаунт: '',


эттоусд: 0,


const setAlert = (msg, color = 'янтарный') => {


setGlobalState('предупреждение', {показать: true, сообщение, цвет})


setTimeout(() => {


setGlobalState('предупреждение', {показать: ложь, сообщение: '', цвет})


}, 5000)


const lastPrice = асинхронный () => {


жду получения(


'https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD'


.then((данные) => data.json())


.then((res) => setGlobalState('ethToUsd', res.USD))


экспорт {useGlobalState, setGlobalState, setAlert, lastPrice}


Файл коннектора ABI


Наконец, у нас есть файл fresher.jsx, который служит интерфейсом между Abi нашего смарт-контракта и внешним интерфейсом. Все коды, необходимые для взаимодействия с нашим смарт-контрактом, хранятся в этом файле, вот код для него.


```javascript


импортировать Web3 из 'web3'


импортировать {setAlert, setGlobalState} из '../store'


импортировать магазин из './abis/Store.json'


const {эфириум} = окно


константа getContract = асинхронная () => {


константа web3 = окно.web3


const networkId = ожидание web3.eth.net.getId()


const networkData = Store.networks[networkId]


если (сетевые данные) {


константный контракт = новый web3.eth.Contract (Store.abi, networkData.address)


контракт на возврат


} еще {


window.alert('Контракт хранилища не развернут в обнаруженной сети.')


const payWithEthers = async (product) => {


пытаться {


константа web3 = окно.web3


постоянный продавец = product.account


постоянный покупатель = продукт.покупатель


постоянная сумма = web3.utils.toWei(product.price.toString(), 'эфир')


const target = Продажи ${product.name}


константный контракт = ожидание getContract()


ждать контракта.методы


.payNow(продавец, цель)


.send({от: покупатель, значение: сумма})


вернуть истину


} поймать (ошибка) {


setAlert(error.message, 'красный')


const connectWallet = асинхронный () => {


пытаться {


if (!ethereum) вернуть предупреждение('Пожалуйста, установите Metamask')


const account = await ethereum.request({метод: 'eth_requestAccounts' })


setGlobalState('connectedAccount', учетные записи[0])


} поймать (ошибка) {


setAlert (JSON.stringify (ошибка), «красный»)


константа loadWeb3 = асинхронная () => {


пытаться {


if (!ethereum) вернуть предупреждение('Пожалуйста, установите Metamask')


window.web3 = новый Web3 (эфириум)


ждать ethereum.enable()


window.web3 = новый Web3 (window.web3.currentProvider)


константа web3 = окно.web3


константные учетные записи = ожидание web3.eth.getAccounts()


setGlobalState('connectedAccount', учетные записи[0])


} поймать (ошибка) {


alert('Пожалуйста, подключите свой кошелек метамаски!')


экспорт { loadWeb3, connectWallet, payWithEthers}


В этой общей папке у нас есть еще одна папка с именем abis, содержащая сгенерированный код ABI для нашего развернутого хранилища. Truffle сгенерировал эти коды для нас, когда мы развернули смарт-контракт в ЧАСТИ ПЕРВОЙ этой статьи.


Убедитесь, что вы включили файл .env в файл .gitignore, это очень важно, чтобы вы не раскрывали свои закрытые ключи в Интернете.


Если об этом все позаботились, то вы должны знать, что вы завершили этот проект.


Поздравляем!!!


Заключение


Технология блокчейн осталась навсегда, в этом новом мире смарт-контрактов, приложений DAO, NFT и DeFi очень важно вооружиться навыками разработки блокчейна.


Не могу дождаться, чтобы увидеть вас в следующей статье, проверьте [демонстрацию] (https://fresher-a5113.web.app/) и [репозиторий GitHub] (https://github.com/Daltonic/freshers). для получения дополнительной информации.


До следующего раза, всего наилучшего!


Об авторе


Госпел Дарлингтон начал свой путь в качестве инженера-программиста в 2016 году. За эти годы он приобрел полноценные навыки работы со стеками JavaScript, такими как React, ReactNative, VueJs и другими.


В настоящее время он работает фрилансером, создает приложения для клиентов, пишет технические руководства, обучая других тому, что делает он.


Евангелие в Дарлингтоне открыто и доступно для вас. Вы можете связаться с ним на LinkedIn, Facebook, Github или на его веб-сайте.



Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE