Что вы будете создавать, см. [живую демонстрацию] (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}


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



<Кнопка


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


размер = "мд"


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


рябь = "свет"


инвалид


Нет на складе