Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Redis

Preference Storage สำหรับ DApps โดยใช้ Metamask กับ Next.js

แอปพลิเคชัน Web3 เช่น DAO และ DAPP กำลังได้รับความนิยมมากขึ้นเรื่อยๆ ภายในพื้นที่ของ Web3 แพลตฟอร์มเหล่านี้ควรให้ประสบการณ์ที่เป็นส่วนตัวและปรับแต่งได้เองมากขึ้นสำหรับผู้ใช้ในขณะที่รักษาข้อมูลประจำตัวของพวกเขาให้เป็นส่วนตัวต่อผู้อื่นหรือแม้กระทั่งไม่รู้จักตัวเอง

ในโครงการนี้ เราจะสำรวจว่าเราจะสามารถปรับปรุงประสบการณ์ของผู้ใช้ในกรณีดังกล่าวได้อย่างไร

การตรวจสอบสิทธิ์ / การตรวจสอบตัวตนผ่าน Wallets

สำหรับแอปพลิเคชั่นมากมาย กระเป๋าเงินบล็อคเชนเช่น Metamask ถูกใช้เพื่อจัดการสินทรัพย์ crypto เช่น ETH กระเป๋าเงินดังกล่าวให้ผู้ใช้สร้างบัญชีในเครือข่ายต่างๆ บัญชีเหล่านี้สร้างขึ้นด้วยคีย์ส่วนตัว อย่างไรก็ตาม แต่ละบัญชีมีที่อยู่สาธารณะที่เป็นตัวแทนของบัญชีเหล่านี้

เนื่องจากทุกคนสามารถแสดงคีย์สาธารณะได้ แต่ธุรกรรมที่เกี่ยวข้องกับคีย์นี้สามารถจัดการได้โดยเจ้าของเท่านั้น การเชื่อมต่อ Wallet เป็นกลไกการตรวจสอบสิทธิ์ที่มั่นคงสำหรับแอปพลิเคชันดังกล่าว

โครงการ

ในโปรเจ็กต์นี้ เราจะใช้ระบบจัดเก็บข้อมูลการกำหนดค่าตามความชอบโดยใช้ Next.js ซึ่งผู้ใช้จะปรับแต่งอินเทอร์เฟซที่มีให้ หมายความว่า เมื่อใดก็ตามที่พวกเขากลับมาที่ไซต์นั้น พวกเขาจะเห็น UI ตามที่ตั้งใจไว้

แนวคิดที่ทรงพลังยิ่งกว่านั้นยังสามารถทำให้อินเทอร์เฟซผู้ใช้เป็นปกติทั่วทั้งแพลตฟอร์มย่อยและข้ามแพลตฟอร์มของบริษัท ด้วยวิธีนี้ เมื่อใดก็ตามที่ผู้ใช้นำทางไปยังไซต์ใดไซต์หนึ่งที่สนับสนุนการตั้งค่าที่พวกเขาตั้งไว้บนไซต์อื่นๆ พวกเขาจะมีประสบการณ์ที่คล้ายกัน

นอกจากนี้ โปรเจ็กต์นี้สามารถปรับเปลี่ยนเพื่อเปลี่ยนจำนวนพารามิเตอร์สำหรับการปรับแต่งได้ ช่วยให้คุณขึ้นรูปเป็นโครงสร้างตามที่คุณต้องการได้

สำหรับโปรเจ็กต์ตัวอย่างนี้ มีเพียง 2 พารามิเตอร์เท่านั้น กล่าวคือ:

  • ธีมของเว็บไซต์
  • คำทักทายสำหรับผู้ใช้

เริ่มต้นใช้งาน

กำหนดค่าตัวแปรสิ่งแวดล้อม Upstash Redis

  • สร้างฐานข้อมูล Redis ฟรีที่ Upstash
  • คัดลอกไฟล์ .env.local.example ไปยัง .env.local (ซึ่ง Git จะไม่สนใจ):
  • UPSTASH_REDIS_REST_URL และ UPSTASH_REDIS_REST_TOKEN สามารถพบได้ที่หน้ารายละเอียดฐานข้อมูลใน Upstash Console

การพึ่งพา

ติดตั้งการพึ่งพา:npm i @upstash/redis @metamask/detect-provider @mui/material @emotion/react @emotion/styled

สร้าง api/store.js ไฟล์

กำหนดค่า Redis SDK และส่งออกฟังก์ชันตัวจัดการ

api/store.js
import { Redis } from "@upstash/redis"
const redis = Redis.fromEnv()

export default async function handler(req, res) {
  const accountID = await JSON.parse(req.body).accountID
  const body = req.body
  const setResult = await redis.set(accountID, body);
  res.status(200).json({ result: setResult })
}

สร้าง api/[accountAddress].js ไฟล์

ในทำนองเดียวกัน กำหนดค่า Redis SDK และส่งออกตัวจัดการ

api/[accountAddress].js
import { Redis } from "@upstash/redis"
const redis = Redis.fromEnv()

export default async function handler(req, res) {
    const accountID = req.query.accountAddress
    const getResult = await redis.get(accountID)
    res.status(200).json({ result: getResult })
}

กำหนดค่า index.js ไฟล์

กำหนดตัวแปรสำหรับโครงการ

index.js
const [accountAddress, setAccountAddress] = useState(null)
const [themePreference, setThemePreference] = useState("light")
const [greetingMessage, setGreetingMessage] = useState("Anonymous Person")
const [userSettings, setUserSettings] = useState(null)

// Check if connection already established. If so, fetch the data.
useEffect(() => {
    checkConnection()
    getPreferences()
}, [accountAddress])

กำลังเชื่อมต่อ Metamask

async function connect() {
    const provider = await detectEthereumProvider()
    console.log("provider:", provider)

    if (provider) {
      console.log('Ethereum successfully detected!')
      provider.request({ method: "eth_requestAccounts" }).then((accounts) => {
        if (!accountAddress) {
          setAccountAddress(accounts[0])
        }
      }).catch((err) => console.log(err))
      console.log("window.ethereum:", window.ethereum)
      getPreferences()
    } else {
      alert('Please install MetaMask!')
    }
  }

ตรวจสอบการเชื่อมต่อเมื่อรีเฟรชหรือนำทางหลังจากผ่านไประยะหนึ่ง

async function checkConnection() {
    const provider = await detectEthereumProvider()
    if (provider) {
      provider
        .request({ method: 'eth_accounts' })
        .then(accounts => {
          setAccountAddress(accounts[0])
        })
        .catch(console.log)
    } else {
      console.log("Not connected, window.ethereum not found")
    }
}

การตั้งค่ากำหนด

async function setPreferences(themePreference, greetingMessage) {
    if (accountAddress) {
      const res = await fetch(`/api/store`, {
        method: "POST",
        body: JSON.stringify({
          accountID: accountAddress,
          themePreference: themePreference,
          greetingMessage: greetingMessage,
        })
      })
      const data = await res.json()
    }
    else {
      alert("No account address detected")
    }
}

หากต้องการรับการตั้งค่า

async function getPreferences(e) {
    if (accountAddress) {
      console.log("Fetching user preferences...")
      const res = await fetch(`/api/${accountAddress}`, { method: "GET" })
      const data = await res.json()

      setUserSettings(data.result)
      if (data.result) {
        setThemePreference(data.result.themePreference)
        setGreetingMessage(data.result.greetingMessage)
      }
    }
    else {
      console.log("No account connected yet!")
    }
}

เปลี่ยนสถานะของตัวแปร

ผูกฟังก์ชันต่อไปนี้เข้ากับช่อง/ปุ่มป้อนข้อมูล ฯลฯ

async function handleDarkMode(e) {
    console.log("themePreference:", themePreference)
    const newPreference = themePreference == "light" ? "dark" : "light"
    setThemePreference(newPreference)
    await setPreferences(newPreference, greetingMessage)
    await getPreferences()
}

async function takeGreetingMessage(e) {
    // submit with enter/return key
    if (e.keyCode == 13) {
        const message = e.target.value
        setGreetingMessage(message)
        console.log(message)
        await setPreferences(themePreference, message)
        await getPreferences()
        e.target.value = ""
    }
}

สร้าง UI อย่างง่ายโดยใช้ฟังก์ชันข้างต้น

ตรวจสอบให้แน่ใจว่าคุณนำเข้าการอ้างอิง Material-UI ที่เกี่ยวข้อง

return (
    <div className={styles.container}>

      <h2>Web3 Preferences Holder</h2>
      <Button variant="contained" onClick={connect}>Connect Metamask</Button>
      <p>
        Lets you keep user preferences on cross-websites
      </p>
      <br />
      <p>For example, take a greeter message from user.</p>
      <TextField label="Call me..." variant="outlined" size="small" onKeyDown={takeGreetingMessage} />
      <br />
      <br />

      <Button onClick={handleDarkMode} variant="contained" size="small" style={{ backgroundColor: "#3D3B3B" }} > Switch Dark Mode </Button>

      <p>Sample Component/Page:</p>
      <Showcase userSettings={userSettings} />

    </div>
)

สร้าง sampleComponent.jsx ในไดเรกทอรี components

นี่คือองค์ประกอบหลักที่แสดงอินเทอร์เฟซเว็บ แอปพลิเคชัน ฯลฯ ของคุณ ส่วนประกอบนี้จะแสดงภาพวิธีการทำงานของระบบ และเป้าหมายหลักที่มีให้ ที่นี่ แยกวิเคราะห์พารามิเตอร์ตามที่คุณต้องการ และสร้างอินเทอร์เฟซตัวอย่างของคุณ

ในกรณีนี้ โปรเจ็กต์ได้รับการกำหนดค่าดังนี้:


import React from "react";
import { useState} from 'react'

import { ThemeProvider, createTheme } from '@mui/material/styles'
import { orange, grey } from '@mui/material/colors'

const lightTheme = createTheme({
  palette: {
    primary: {
      main: grey[400],
    },
  }
})

const darkTheme = createTheme({
  palette: {
    primary: {
      main: orange[400],
    },
  }
})

export default function Showcase(parameters) {

  const userSettings = parameters.userSettings
  const [theme, setTheme] = useState("light")
  const [greetingMessage, setGreetingMessage] = useState("Anonymous Person")

  const items = []
  if (userSettings) {

    const obj = userSettings[0]

    for (const key in userSettings) {
      items.push(<li key={key}> {key}: {userSettings[key]} </li>)
    }

    if (userSettings["themePreference"] != theme) {
      setTheme(userSettings["themePreference"] == "light" ? "light" : "dark")
    }

    if (!greetingMessage || userSettings["greetingMessage"] != greetingMessage) {
      if (userSettings["greetingMessage"]) {
        setGreetingMessage(userSettings["greetingMessage"])
      }
      else {
        setGreetingMessage("not the same message")
      }
    }
  }

  return (
    <div>
      <div style={{
        padding: 10,
        margin: 10,
        backgroundColor: theme == "light" ? "grey" : "orange",
        border: "solid",
        borderWidth: "30px",
        borderColor: theme == "light" ? "#B2B2B2" : "black"
      }}>
        <ThemeProvider
          theme={theme == "light" ? lightTheme : darkTheme}
        >

          <h2>Hi, {greetingMessage}!</h2>
          <p>User and their preferences:</p>
          {items}

        </ThemeProvider>

      </div>
    </div>
  );
}

เวิร์กโฟลว์

ผู้ใช้ยังไม่ได้เชื่อมต่อผ่าน Metamask เทมเพลตเริ่มต้น

Preference Storage สำหรับ DApps โดยใช้ Metamask กับ Next.js

ผู้ใช้เชื่อมต่อผ่าน Metamask เป็นครั้งแรก เทมเพลตเริ่มต้น

Preference Storage สำหรับ DApps โดยใช้ Metamask กับ Next.js

  • ผู้ใช้ป้อนชื่อที่ต้องการเห็นเมื่อเข้าสู่แพลตฟอร์ม
  • ผู้ใช้เลือกระหว่างธีม คือสว่างและมืด

ตั้งค่ากำหนดผู้ใช้แล้ว จากนี้ไป อินเทอร์เฟซเดียวกันสามารถแสดงในแพลตฟอร์มใดก็ได้ที่สนับสนุนอินเทอร์เฟซการตั้งค่าที่มีให้ เทมเพลตที่ผู้ใช้กำหนดเอง

Preference Storage สำหรับ DApps โดยใช้ Metamask กับ Next.js

คอมโพเนนต์แสดงการตั้งค่าที่กำหนดโดยผู้ใช้ในรูปแบบข้อความ คุณสามารถแยกวิเคราะห์ได้ตามต้องการ

ดังที่คุณเห็นในตัวอย่างง่ายๆ นี้ คุณสามารถกำหนดพารามิเตอร์องค์ประกอบใดๆ ที่คุณแสดงให้ผู้ใช้เห็น คุณสามารถเพิ่มในโครงการนี้ได้ตลอดเวลาโดยการปรับปรุงการออกแบบและเพิ่มจำนวนพารามิเตอร์ แต่ตรรกะพื้นฐานยังคงเหมือนเดิม

คำสุดท้าย

ดูการสาธิตของโครงการได้ที่นี่

หากต้องการดูโครงการที่เสร็จแล้ว ไปที่ Github Repo ของโครงการ

คุณจะเห็นปุ่มปรับใช้อย่างรวดเร็วสำหรับการปรับใช้ Vercel ให้คุณปรับใช้โปรเจ็กต์ได้อย่างรวดเร็ว โดยสร้างการผสานรวม Upstash Redis โดยอัตโนมัติ

เรารอคอยที่จะได้ยินความคิดและความคิดของคุณ คุณสามารถติดต่อเราได้ทาง Twitter หรือ Discord