feat: run lint: fix and yarn-deduplicate

This commit is contained in:
morris.lin
2023-08-25 15:35:30 +08:00
parent a0e81edd14
commit 20fcbe3204
34 changed files with 64371 additions and 64054 deletions

6
.vscode/launch.json vendored
View File

@@ -4,7 +4,6 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch Chrome",
"request": "launch",
@@ -23,7 +22,10 @@
"compounds": [
{
"name": "Debug Frontend & Backend",
"configurations": ["Launch Chrome", "Attach to backend process TS-Node"]
"configurations": [
"Launch Chrome",
"Attach to backend process TS-Node"
]
}
]
}

125146
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,34 +1,34 @@
{
"name": "social-tw-website",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"private": true,
"workspaces": [
"packages/*"
],
"scripts": {
"install": "lerna bootstrap",
"build": "lerna run build",
"circuits": "yarn workspace @unirep-app/circuits run",
"contracts": "yarn workspace @unirep-app/contracts run",
"frontend": "yarn workspace @unirep-app/frontend run",
"relay": "yarn workspace @unirep-app/relay run",
"start": "node scripts/start.mjs",
"linkUnirep": "sh ./scripts/linkUnirep.sh",
"copyUnirep": "sh ./scripts/copyUnirep.sh",
"lint": "prettier .",
"lint:fix": "yarn lint --write",
"lint:check": "yarn lint --check"
},
"devDependencies": {
"@types/jest": "^29.5.4",
"@types/testing-library__jest-dom": "^6.0.0",
"hardhat": "^2.17.1",
"lerna": "^6.0.1",
"node-fetch": "^3.3.0"
},
"dependencies": {
"prettier": "^2.8.4"
}
"name": "social-tw-website",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"private": true,
"workspaces": [
"packages/*"
],
"scripts": {
"install": "lerna bootstrap",
"build": "lerna run build",
"circuits": "yarn workspace @unirep-app/circuits run",
"contracts": "yarn workspace @unirep-app/contracts run",
"frontend": "yarn workspace @unirep-app/frontend run",
"relay": "yarn workspace @unirep-app/relay run",
"start": "node scripts/start.mjs",
"linkUnirep": "sh ./scripts/linkUnirep.sh",
"copyUnirep": "sh ./scripts/copyUnirep.sh",
"lint": "prettier .",
"lint:fix": "yarn lint --write",
"lint:check": "yarn lint --check"
},
"devDependencies": {
"@types/jest": "^29.5.4",
"@types/testing-library__jest-dom": "^6.0.0",
"hardhat": "^2.17.1",
"lerna": "^6.0.1",
"node-fetch": "^3.3.0"
},
"dependencies": {
"prettier": "^2.8.4"
}
}

View File

@@ -4,10 +4,7 @@
"outDir": "./dist",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"types": [
"jest",
"node"
]
"types": ["jest", "node"]
},
"exclude": ["node_modules/**"],
"include": ["./src", "./config", "./provers"]

View File

@@ -1 +1,317 @@
[{"inputs":[{"internalType":"contract Unirep","name":"_unirep","type":"address"},{"internalType":"contract EpochKeyVerifierHelper","name":"_epkHelper","type":"address"},{"internalType":"contract IVerifier","name":"_dataVerifier","type":"address"},{"internalType":"uint48","name":"_epochLength","type":"uint48"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint160","name":"attesterId","type":"uint160"}],"name":"AttesterIdNotMatch","type":"error"},{"inputs":[{"internalType":"uint256","name":"hashUserId","type":"uint256"},{"internalType":"enum UnirepApp.RegisterStatus","name":"status","type":"uint8"}],"name":"UserAlreadySignedUp","type":"error"},{"inputs":[{"internalType":"uint256","name":"hashUserId","type":"uint256"}],"name":"UserInitExpiry","type":"error"},{"inputs":[{"internalType":"uint256","name":"hashUserId","type":"uint256"}],"name":"UserInitStatusInvalid","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"epochKey","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"postId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"epoch","type":"uint256"},{"indexed":false,"internalType":"string","name":"content","type":"string"}],"name":"Post","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"hashUserId","type":"uint256"}],"name":"UserInitSuccess","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"hashUserId","type":"uint256"}],"name":"UserSignUpSuccess","type":"event"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"epochKeyPostIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"epochKeyPostVoteMap","outputs":[{"internalType":"uint256","name":"upVote","type":"uint256"},{"internalType":"uint256","name":"downVote","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"hashUserId","type":"uint256"}],"name":"initUserStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"publicSignals","type":"uint256[]"},{"internalType":"uint256[8]","name":"proof","type":"uint256[8]"},{"internalType":"string","name":"content","type":"string"}],"name":"post","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"proofNullifier","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"hashUserId","type":"uint256"}],"name":"queryUserStatus","outputs":[{"internalType":"enum UnirepApp.RegisterStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"epochKey","type":"uint256"},{"internalType":"uint48","name":"targetEpoch","type":"uint48"},{"internalType":"uint256","name":"fieldIndex","type":"uint256"},{"internalType":"uint256","name":"val","type":"uint256"}],"name":"submitAttestation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"epochKey","type":"uint256"},{"internalType":"uint48","name":"targetEpoch","type":"uint48"},{"internalType":"uint256[]","name":"fieldIndices","type":"uint256[]"},{"internalType":"uint256[]","name":"vals","type":"uint256[]"}],"name":"submitManyAttestations","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unirep","outputs":[{"internalType":"contract Unirep","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"publicSignals","type":"uint256[]"},{"internalType":"uint256[8]","name":"proof","type":"uint256[8]"},{"internalType":"uint256","name":"hashUserId","type":"uint256"},{"internalType":"bool","name":"fromServer","type":"bool"}],"name":"userSignUp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[5]","name":"publicSignals","type":"uint256[5]"},{"internalType":"uint256[8]","name":"proof","type":"uint256[8]"}],"name":"verifyDataProof","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]
[
{
"inputs": [
{
"internalType": "contract Unirep",
"name": "_unirep",
"type": "address"
},
{
"internalType": "contract EpochKeyVerifierHelper",
"name": "_epkHelper",
"type": "address"
},
{
"internalType": "contract IVerifier",
"name": "_dataVerifier",
"type": "address"
},
{
"internalType": "uint48",
"name": "_epochLength",
"type": "uint48"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [
{
"internalType": "uint160",
"name": "attesterId",
"type": "uint160"
}
],
"name": "AttesterIdNotMatch",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "hashUserId",
"type": "uint256"
},
{
"internalType": "enum UnirepApp.RegisterStatus",
"name": "status",
"type": "uint8"
}
],
"name": "UserAlreadySignedUp",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "hashUserId",
"type": "uint256"
}
],
"name": "UserInitExpiry",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "hashUserId",
"type": "uint256"
}
],
"name": "UserInitStatusInvalid",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint256",
"name": "epochKey",
"type": "uint256"
},
{
"indexed": true,
"internalType": "uint256",
"name": "postId",
"type": "uint256"
},
{
"indexed": true,
"internalType": "uint256",
"name": "epoch",
"type": "uint256"
},
{
"indexed": false,
"internalType": "string",
"name": "content",
"type": "string"
}
],
"name": "Post",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "hashUserId",
"type": "uint256"
}
],
"name": "UserInitSuccess",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "hashUserId",
"type": "uint256"
}
],
"name": "UserSignUpSuccess",
"type": "event"
},
{
"inputs": [
{ "internalType": "uint256", "name": "", "type": "uint256" }
],
"name": "epochKeyPostIndex",
"outputs": [
{ "internalType": "uint256", "name": "", "type": "uint256" }
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{ "internalType": "uint256", "name": "", "type": "uint256" },
{ "internalType": "uint256", "name": "", "type": "uint256" }
],
"name": "epochKeyPostVoteMap",
"outputs": [
{ "internalType": "uint256", "name": "upVote", "type": "uint256" },
{ "internalType": "uint256", "name": "downVote", "type": "uint256" }
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "hashUserId",
"type": "uint256"
}
],
"name": "initUserStatus",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256[]",
"name": "publicSignals",
"type": "uint256[]"
},
{
"internalType": "uint256[8]",
"name": "proof",
"type": "uint256[8]"
},
{ "internalType": "string", "name": "content", "type": "string" }
],
"name": "post",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{ "internalType": "bytes32", "name": "", "type": "bytes32" }
],
"name": "proofNullifier",
"outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "hashUserId",
"type": "uint256"
}
],
"name": "queryUserStatus",
"outputs": [
{
"internalType": "enum UnirepApp.RegisterStatus",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "epochKey",
"type": "uint256"
},
{
"internalType": "uint48",
"name": "targetEpoch",
"type": "uint48"
},
{
"internalType": "uint256",
"name": "fieldIndex",
"type": "uint256"
},
{ "internalType": "uint256", "name": "val", "type": "uint256" }
],
"name": "submitAttestation",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "epochKey",
"type": "uint256"
},
{
"internalType": "uint48",
"name": "targetEpoch",
"type": "uint48"
},
{
"internalType": "uint256[]",
"name": "fieldIndices",
"type": "uint256[]"
},
{ "internalType": "uint256[]", "name": "vals", "type": "uint256[]" }
],
"name": "submitManyAttestations",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "unirep",
"outputs": [
{ "internalType": "contract Unirep", "name": "", "type": "address" }
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256[]",
"name": "publicSignals",
"type": "uint256[]"
},
{
"internalType": "uint256[8]",
"name": "proof",
"type": "uint256[8]"
},
{
"internalType": "uint256",
"name": "hashUserId",
"type": "uint256"
},
{ "internalType": "bool", "name": "fromServer", "type": "bool" }
],
"name": "userSignUp",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256[5]",
"name": "publicSignals",
"type": "uint256[5]"
},
{
"internalType": "uint256[8]",
"name": "proof",
"type": "uint256[8]"
}
],
"name": "verifyDataProof",
"outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
"stateMutability": "view",
"type": "function"
}
]

View File

@@ -1,27 +1,27 @@
name: Playwright Tests
on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
push:
branches: [main, master]
pull_request:
branches: [main, master]
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Install dependencies
run: yarn
- name: Install Playwright Browsers
run: yarn playwright install --with-deps
- name: Run Playwright tests
run: yarn playwright test
- uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30
test:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Install dependencies
run: yarn
- name: Install Playwright Browsers
run: yarn playwright install --with-deps
- name: Run Playwright tests
run: yarn playwright test
- uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30

View File

@@ -1,6 +1,6 @@
module.exports = {
presets: [
['@babel/preset-env', {targets: {node: 'current'}}],
['@babel/preset-env', { targets: { node: 'current' } }],
'@babel/preset-typescript',
],
};
}

View File

@@ -1,9 +1,10 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'jsdom',
moduleNameMapper: {
"@testing-library/react": "<rootDir>/node_modules/@testing-library/react",
"@types/jest": "jest"
},
};
preset: 'ts-jest',
testEnvironment: 'jsdom',
moduleNameMapper: {
'@testing-library/react':
'<rootDir>/node_modules/@testing-library/react',
'@types/jest': 'jest',
},
}

View File

@@ -1,4 +1,5 @@
# Login and Sign up Flow
1. Follow the process in README (at root) to initialize the environment
2. Add .env in the packages/relay below is a public sample for test
3. Go to localhost:3000/login to start
@@ -6,5 +7,5 @@
5. Login with twitter then redirect
6. Choose sign up with server or wallet
7. Navigate to home
8. Process sing up
9. If success then update the states
8. Process sing up
9. If success then update the states

View File

@@ -1,11 +1,9 @@
import React from 'react';
import BaseLayout from '../../layouts/BaseLayout';
import {render, screen} from '@testing-library/react'
import React from 'react'
import BaseLayout from '../../layouts/BaseLayout'
import { render, screen } from '@testing-library/react'
import '@testing-library/jest-dom'
import {expect} from "@jest/globals";
import { expect } from '@jest/globals'
test("BaseLayout should render", () => {
render(
<BaseLayout/>
);
});
test('BaseLayout should render', () => {
render(<BaseLayout />)
})

View File

@@ -1,17 +1,17 @@
import React from 'react';
import {render, screen} from '@testing-library/react';
import OnboardingLayout from '../../layouts/OnboardingLayout';
import {UserProvider} from '../../contexts/User';
import React from 'react'
import { render, screen } from '@testing-library/react'
import OnboardingLayout from '../../layouts/OnboardingLayout'
import { UserProvider } from '../../contexts/User'
import '@testing-library/jest-dom'
import {MemoryRouter} from "react-router-dom";
import {expect} from "@jest/globals";
import { MemoryRouter } from 'react-router-dom'
import { expect } from '@jest/globals'
test("OnboardingLayout should render", () => {
test('OnboardingLayout should render', () => {
render(
<MemoryRouter>
<UserProvider>
<OnboardingLayout/>
<OnboardingLayout />
</UserProvider>
</MemoryRouter>
);
});
)
})

View File

@@ -1,32 +1,32 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';
import ErrorPage from '../../pages/ErrorPage';
import { useRouteError } from 'react-router-dom';
import React from 'react'
import { render, screen } from '@testing-library/react'
import '@testing-library/jest-dom'
import ErrorPage from '../../pages/ErrorPage'
import { useRouteError } from 'react-router-dom'
// Mock the useRouteError hook from react-router-dom
jest.mock('react-router-dom', () => {
return ({
return {
// @ts-ignore
...jest.requireActual('react-router-dom'),
useRouteError: jest.fn(),
});
});
}
})
describe('<ErrorPage />', () => {
it('displays the statusText of the error', () => {
// Mock the hook to return a specific error
// @ts-ignore
(useRouteError as jest.Mock).mockReturnValue({
;(useRouteError as jest.Mock).mockReturnValue({
message: 'A test error',
statusText: '404 Not Found',
});
})
render(<ErrorPage />);
render(<ErrorPage />)
// @ts-ignore
expect(screen.getByText('404 Not Found')).toBeInTheDocument();
});
expect(screen.getByText('404 Not Found')).toBeInTheDocument()
})
// Add more tests as needed for other scenarios or other parts of the component
});
})

View File

@@ -1,23 +1,23 @@
import React from 'react';
import {render, screen} from '@testing-library/react';
import Login from '../../pages/Login';
import React from 'react'
import { render, screen } from '@testing-library/react'
import Login from '../../pages/Login'
import '@testing-library/jest-dom'
import {expect} from "@jest/globals";
import {MemoryRouter} from "react-router-dom";
import {UserProvider} from "../../contexts/User";
import { expect } from '@jest/globals'
import { MemoryRouter } from 'react-router-dom'
import { UserProvider } from '../../contexts/User'
test("Login should render", () => {
test('Login should render', () => {
render(
<MemoryRouter>
<UserProvider>
<Login/>
<Login />
</UserProvider>
</MemoryRouter>
);
)
// @ts-ignore
expect(screen.getByAltText('UniRep Logo')).toBeInTheDocument();
expect(screen.getByAltText('UniRep Logo')).toBeInTheDocument()
// @ts-ignore
expect(screen.getByText('Unirep Social TW')).toBeInTheDocument();
expect(screen.getByText('Unirep Social TW')).toBeInTheDocument()
// ... Add more tests as needed ...
});
})

View File

@@ -23,14 +23,29 @@ const AuthForm: React.FC<AuthFormProps> = ({
method,
onSignup,
onLogin,
}
) => {
}) => {
const navigate = useNavigate()
const { setIsSignupLoading, isSignupLoading, handleServerSignMessage, handleWalletSignMessage, signup } = useUser()
const {
setIsSignupLoading,
isSignupLoading,
handleServerSignMessage,
handleWalletSignMessage,
signup,
} = useUser()
const [noteStatus, setNoteStatus] = useState('close')
const twitterVerify = useTwitterVerify(SERVER)
const signupWithWallet = useSignUpWithWallet(navigate, setIsSignupLoading, handleWalletSignMessage, signup)
const signupWithServer = useSignupWithServer(navigate, setIsSignupLoading, handleServerSignMessage, signup)
const signupWithWallet = useSignUpWithWallet(
navigate,
setIsSignupLoading,
handleWalletSignMessage,
signup
)
const signupWithServer = useSignupWithServer(
navigate,
setIsSignupLoading,
handleServerSignMessage,
signup
)
const authVarients = {
hidden: { opacity: 0 },
@@ -39,62 +54,61 @@ const AuthForm: React.FC<AuthFormProps> = ({
transition: {
delay: 1,
duration: 1,
ease: "easeInOut",
ease: 'easeInOut',
},
},
}
const sendSignupStepContent =
const sendSignupStepContent = (
<>
<LoginButton
isLoading={isSignupLoading}
onClick={signupWithWallet}
title='錢包註冊'
subTitle='使用 MetaMask 錢包進行登入'
color='#2F9CAF'
text='MetaMask 錢包'
title="錢包註冊"
subTitle="使用 MetaMask 錢包進行登入"
color="#2F9CAF"
text="MetaMask 錢包"
setNoteStatus={() => setNoteStatus('metamask')}
/>
<LoginButton
isLoading={isSignupLoading}
onClick={signupWithServer}
title='直接註冊'
subTitle='沒有錢包嗎? 沒關係! 可以直接使用 Server 註冊'
color='#DB7622'
text='Server 註冊'
title="直接註冊"
subTitle="沒有錢包嗎? 沒關係! 可以直接使用 Server 註冊"
color="#DB7622"
text="Server 註冊"
setNoteStatus={() => setNoteStatus('server')}
/>
</>
)
const firtSignupStepContent = method === '' ?
(
const firtSignupStepContent =
method === '' ? (
<>
<LoginButton
isLoading={isSignupLoading}
onClick={() => { }}
title='立即登入'
subTitle='歡迎提供你的獨到見解!'
color='#2F9CAF'
onClick={() => {}}
title="立即登入"
subTitle="歡迎提供你的獨到見解!"
color="#2F9CAF"
/>
<LoginButton
isLoading={isSignupLoading}
onClick={onSignup}
title='立即註冊'
subTitle='只要兩步驟,即可安全匿名分享你的想法!'
color='#FF892A'
title="立即註冊"
subTitle="只要兩步驟,即可安全匿名分享你的想法!"
color="#FF892A"
/>
</>
)
:
(
) : (
<>
<LoginButton
<LoginButton
isLoading={isSignupLoading}
icon={BsTwitter}
onClick={twitterVerify}
title='使用 Twitter 帳號登入'
subTitle='歡迎提供你的獨到見解!'
color='#2F9CAF'
title="使用 Twitter 帳號登入"
subTitle="歡迎提供你的獨到見解!"
color="#2F9CAF"
/>
</>
)
@@ -119,4 +133,3 @@ const AuthForm: React.FC<AuthFormProps> = ({
}
export default AuthForm

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { IoIosMore } from 'react-icons/io';
import { BiSolidLike, BiSolidDislike, BiCommentDetail } from 'react-icons/bi';
import { motion } from 'framer-motion';
import React from 'react'
import { IoIosMore } from 'react-icons/io'
import { BiSolidLike, BiSolidDislike, BiCommentDetail } from 'react-icons/bi'
import { motion } from 'framer-motion'
interface DemoPostProps {
text: string
@@ -16,22 +16,22 @@ const DemoPost: React.FC<DemoPostProps> = ({
likes,
dislikes,
comments,
index
index,
}) => {
const getOpacity = (index: number): number => {
switch (index) {
case 1:
return 0.9;
return 0.9
case 2:
return 0.2;
return 0.2
case 4:
return 0.15;
return 0.15
default:
return 0.1;
return 0.1
}
};
}
const opacity = getOpacity(index);
const opacity = getOpacity(index)
const postVarient = {
visible: { opacity: 1 },
@@ -40,58 +40,48 @@ const DemoPost: React.FC<DemoPostProps> = ({
transition: {
delay: 1,
duration: 1,
ease: "easeInOut",
ease: 'easeInOut',
},
}
};
},
}
return (
<motion.div
className='max-w-[600px] flex flex-col justify-between px-5 py-4 bg-[#FFFFFFE5] w-11/12 h-[164px] rounded-xl'
<motion.div
className="max-w-[600px] flex flex-col justify-between px-5 py-4 bg-[#FFFFFFE5] w-11/12 h-[164px] rounded-xl"
variants={postVarient}
initial="visible"
animate="hidden"
>
<div className='flex justify-between'>
<div className='flex justify-center items-center'>
<p className='mr-5 border-2 rounded-full border-white text-center'>
<div className="flex justify-between">
<div className="flex justify-center items-center">
<p className="mr-5 border-2 rounded-full border-white text-center">
🎃
</p>
<span className='text-[10px] text-black font-medium'>
<span className="text-[10px] text-black font-medium">
</span>
</div>
<IoIosMore
className='text-[#8F8F8F]'
/>
<IoIosMore className="text-[#8F8F8F]" />
</div>
<p className='text-xs font-semibold'>
{text}...
</p>
<div className='flex gap-2'>
<div className='flex items-center gap-1'>
<div className='text-white bg-[#DB7622] rounded-full p-[5px]'>
<BiSolidLike className='text-sm' />
<p className="text-xs font-semibold">{text}...</p>
<div className="flex gap-2">
<div className="flex items-center gap-1">
<div className="text-white bg-[#DB7622] rounded-full p-[5px]">
<BiSolidLike className="text-sm" />
</div>
<p className='text-[10px]'>
{likes}
</p>
<p className="text-[10px]">{likes}</p>
</div>
<div className='flex items-center gap-1'>
<div className='text-white bg-[black] rounded-full p-[5px]'>
<BiSolidDislike className='text-sm' />
<div className="flex items-center gap-1">
<div className="text-white bg-[black] rounded-full p-[5px]">
<BiSolidDislike className="text-sm" />
</div>
<p className='text-[10px]'>
{dislikes}
</p>
<p className="text-[10px]">{dislikes}</p>
</div>
<div className='flex items-center gap-1'>
<div className='text-white bg-[#2F9CAF] rounded-full p-[5px]'>
<BiCommentDetail className='text-sm' />
<div className="flex items-center gap-1">
<div className="text-white bg-[#2F9CAF] rounded-full p-[5px]">
<BiCommentDetail className="text-sm" />
</div>
<p className='text-[10px] font-medium'>
{comments}
</p>
<p className="text-[10px] font-medium">{comments}</p>
</div>
</div>
</motion.div>
@@ -99,4 +89,3 @@ const DemoPost: React.FC<DemoPostProps> = ({
}
export default DemoPost

View File

@@ -1,56 +1,57 @@
import React from 'react'
import DemoPost from './DemoPost'
// TODO: opacity animation
const DemoPostList = () => {
const data = [
{
text: '今天真是一個美好的日子!我終於完成了我夢寐以求的目標:跑完全馬拉松!這個挑戰對我來說真的非常艱巨,但我堅持下來了。我要特別感謝我的家人和朋友對我一直以來的支持和鼓勵。無論你們在生活中面對什麼',
likes: 214,
dislikes: 26,
comments: 16,
},
{
text: '今天真是一個美好的日子!我終於完成了我夢寐以求的目標:跑完全馬拉松!這個挑戰對我來說真的非常艱巨,但我堅持下來了。我要特別感謝我的家人和朋友對我一直以來的支持和鼓勵。無論你們在生活中面對什麼',
likes: 214,
dislikes: 26,
comments: 16,
},
{
text: '今天真是一個美好的日子!我終於完成了我夢寐以求的目標:跑完全馬拉松!這個挑戰對我來說真的非常艱巨,但我堅持下來了。我要特別感謝我的家人和朋友對我一直以來的支持和鼓勵。無論你們在生活中面對什麼',
likes: 214,
dislikes: 26,
comments: 16,
},
{
text: '今天真是一個美好的日子!我終於完成了我夢寐以求的目標:跑完全馬拉松!這個挑戰對我來說真的非常艱巨,但我堅持下來了。我要特別感謝我的家人和朋友對我一直以來的支持和鼓勵。無論你們在生活中面對什麼',
likes: 214,
dislikes: 26,
comments: 16,
}
];
const data = [
{
text: '今天真是一個美好的日子!我終於完成了我夢寐以求的目標:跑完全馬拉松!這個挑戰對我來說真的非常艱巨,但我堅持下來了。我要特別感謝我的家人和朋友對我一直以來的支持和鼓勵。無論你們在生活中面對什麼',
likes: 214,
dislikes: 26,
comments: 16,
},
{
text: '今天真是一個美好的日子!我終於完成了我夢寐以求的目標:跑完全馬拉松!這個挑戰對我來說真的非常艱巨,但我堅持下來了。我要特別感謝我的家人和朋友對我一直以來的支持和鼓勵。無論你們在生活中面對什麼',
likes: 214,
dislikes: 26,
comments: 16,
},
{
text: '今天真是一個美好的日子!我終於完成了我夢寐以求的目標:跑完全馬拉松!這個挑戰對我來說真的非常艱巨,但我堅持下來了。我要特別感謝我的家人和朋友對我一直以來的支持和鼓勵。無論你們在生活中面對什麼',
likes: 214,
dislikes: 26,
comments: 16,
},
{
text: '今天真是一個美好的日子!我終於完成了我夢寐以求的目標:跑完全馬拉松!這個挑戰對我來說真的非常艱巨,但我堅持下來了。我要特別感謝我的家人和朋友對我一直以來的支持和鼓勵。無論你們在生活中面對什麼',
likes: 214,
dislikes: 26,
comments: 16,
},
]
return (
<div className='
return (
<div
className="
flex
flex-col
items-center
justify-center
gap-6
'>
{data.map((item, i) => (
<DemoPost
key={i}
index={i}
text={item.text}
likes={item.likes}
dislikes={item.dislikes}
comments={item.comments}
/>
))}
</div>
)
"
>
{data.map((item, i) => (
<DemoPost
key={i}
index={i}
text={item.text}
likes={item.likes}
dislikes={item.dislikes}
comments={item.comments}
/>
))}
</div>
)
}
export default DemoPostList

View File

@@ -1,6 +1,6 @@
import { clsx } from 'clsx';
import { clsx } from 'clsx'
import React from 'react'
import { IconType, icons } from 'react-icons';
import { IconType, icons } from 'react-icons'
interface LoginButtonProps {
icon?: IconType
@@ -22,11 +22,11 @@ const LoginButton: React.FC<LoginButtonProps> = ({
title,
subTitle,
color,
setNoteStatus
setNoteStatus,
}) => {
return (
<button
type='button'
type="button"
onClick={onClick}
disabled={isLoading}
className={`
@@ -44,8 +44,10 @@ const LoginButton: React.FC<LoginButtonProps> = ({
bg-opacity-70
`}
>
<span className='text-white font-semibold text-2xl tracking-wider'>{title}</span>
<span className='text-xs tracking-wider'>{subTitle}</span>
<span className="text-white font-semibold text-2xl tracking-wider">
{title}
</span>
<span className="text-xs tracking-wider">{subTitle}</span>
</button>
)
}

View File

@@ -1,25 +1,25 @@
import { clsx } from "clsx"
import React from "react"
import { clsx } from 'clsx'
import React from 'react'
interface StepInfoProps {
hashUserId: string | null
}
const StepInfo: React.FC<StepInfoProps> = ({
hashUserId,
}) => {
const StepInfo: React.FC<StepInfoProps> = ({ hashUserId }) => {
return (
<>
<div className='
<div
className="
flex
w-[80px]
flex-col
justify-center
items-center
gap-2'
gap-2"
>
<div
className={clsx(`
className={clsx(
`
text-white
w-[60px]
h-[60px]
@@ -33,40 +33,45 @@ const StepInfo: React.FC<StepInfoProps> = ({
`,
hashUserId && 'border-[5px] border-white'
)}
>1</div>
<div className='
>
1
</div>
<div
className="
text-white
text-sm
flex
flex-col
justify-center
items-center
tracking-wide'
tracking-wide"
>
<span>Twitter</span>
<span></span>
</div>
</div>
<div className='
<div
className="
w-[50px]
mb-10
flex
justify-between
items-center
'
>
<span className='bg-[#FF892A] h-1 w-1'></span>
<span className='bg-[#FF892A] h-1 w-2'></span>
<span className='bg-[#FF892A] h-1 w-2'></span>
<span className='bg-[#FF892A] h-1 w-1'></span>
"
>
<span className="bg-[#FF892A] h-1 w-1"></span>
<span className="bg-[#FF892A] h-1 w-2"></span>
<span className="bg-[#FF892A] h-1 w-2"></span>
<span className="bg-[#FF892A] h-1 w-1"></span>
</div>
<div
className={clsx(
`flex w-[80px] flex-col justify-center items-center gap-2`,
!hashUserId && 'opacity-30'
)}>
)}
>
<div
className='
className="
text-white
w-[60px]
h-[60px]
@@ -77,16 +82,19 @@ const StepInfo: React.FC<StepInfoProps> = ({
bg-[#FF892A]
rounded-full
text-[30px]
'
>2</div>
<div className='
"
>
2
</div>
<div
className="
text-white
text-sm
flex
flex-col
justify-center
items-center
tracking-wide'
tracking-wide"
>
<span></span>
<span>Or </span>

View File

@@ -10,11 +10,7 @@ interface ModalProps {
children: React.ReactNode
}
const Modal: React.FC<ModalProps> = ({
isOpen,
onClose,
children
}) => {
const Modal: React.FC<ModalProps> = ({ isOpen, onClose, children }) => {
const modalVariants = {
hidden: { opacity: 0 },
visible: {
@@ -43,28 +39,28 @@ const Modal: React.FC<ModalProps> = ({
return (
<>
<motion.div
className='
className="
fixed
inset-0
z-50
bg-black
bg-opacity-90
h-full
'
"
variants={modalVariants}
initial='hidden'
animate='visible'
initial="hidden"
animate="visible"
/>
<motion.div
className='
className="
fixed
inset-0
z-[60]
bg-opacity-80
'
"
variants={chidrenVarients}
initial='hidden'
animate='visible'
initial="hidden"
animate="visible"
>
{children}
</motion.div>

View File

@@ -1,6 +1,6 @@
import React from 'react';
import { IconType } from 'react-icons';
import Modal from './Modal';
import React from 'react'
import { IconType } from 'react-icons'
import Modal from './Modal'
interface NoteModallProps {
noteStatus: string
@@ -8,43 +8,65 @@ interface NoteModallProps {
onClose: () => void
}
const NoteModal: React.FC<NoteModallProps> = ({
noteStatus,
icon: Icon,
onClose
onClose,
}) => {
let content;
let content
switch (noteStatus) {
case 'metamask':
content = (
<>
<p className='underline font-semibold'> MetaMask </p>
<p>MetaMask Ethereum便DApps使 MetaMask ETH</p>
<p>MetaMask 使使 MetaMask MetaMask 使便</p>
<p>MetaMask 使便使MetaMask </p>
<p className="underline font-semibold">
MetaMask
</p>
<p>
MetaMask
Ethereum便DApps使
MetaMask
ETH
</p>
<p>
MetaMask
使使
MetaMask
MetaMask
使便
</p>
<p>
MetaMask
使便使MetaMask
</p>
</>
);
break;
)
break
case 'server':
content = (
<>
<p className='underline font-semibold'> Server </p>
<p> Metamask Server </p>
<p>使 Server 使</p>
<p className="underline font-semibold">
Server
</p>
<p>
Metamask Server
</p>
<p>
使 Server
使
</p>
</>
);
break;
)
break
}
return (
<Modal
isOpen={noteStatus !== 'close'}
>
<div className='flex flex-col justify-center items-center h-full p-4'>
<div className='relative p-12 flex flex-col gap-4 bg-white max-w-[600px] overflow-auto leading-7 tex-[15px] tracking-wider rounded-lg'>
<Icon
className='absolute right-12 cursor-pointer'
<Modal isOpen={noteStatus !== 'close'}>
<div className="flex flex-col justify-center items-center h-full p-4">
<div className="relative p-12 flex flex-col gap-4 bg-white max-w-[600px] overflow-auto leading-7 tex-[15px] tracking-wider rounded-lg">
<Icon
className="absolute right-12 cursor-pointer"
size={24}
onClick={onClose}
/>

View File

@@ -1,8 +1,7 @@
import React from 'react';
import { motion } from 'framer-motion';
import React from 'react'
import { motion } from 'framer-motion'
const Forwording = () => {
const upvoteVariants = {
hidden: { opacity: 0 },
visible: {
@@ -13,7 +12,7 @@ const Forwording = () => {
ease: 'easeInOut',
},
},
};
}
const downvoteVariants = {
hidden: { opacity: 0 },
@@ -26,7 +25,7 @@ const Forwording = () => {
ease: 'easeInOut',
},
},
};
}
const commentVariants = {
hidden: { opacity: 0 },
@@ -39,7 +38,7 @@ const Forwording = () => {
ease: 'easeInOut',
},
},
};
}
const logoColoredVariants = {
hidden: { opacity: 0 },
@@ -52,7 +51,7 @@ const Forwording = () => {
ease: 'easeInOut',
},
},
};
}
const logoWhiteVariants = {
hidden: { opacity: 0 },
@@ -64,57 +63,54 @@ const Forwording = () => {
ease: 'easeInOut',
},
},
};
}
return (
<div className='w-full h-full flex justify-center items-center'>
<div className='flex flex-col justiy-center items-center'>
<div className='relative mb-2 w-[120px] h-[120px]'>
<div className="w-full h-full flex justify-center items-center">
<div className="flex flex-col justiy-center items-center">
<div className="relative mb-2 w-[120px] h-[120px]">
<motion.img
src={require('../../../public/unirep_logo_colored.png')}
className='absolute inset-0'
className="absolute inset-0"
variants={logoColoredVariants}
initial='hidden'
animate='visible'
initial="hidden"
animate="visible"
/>
<motion.img
src={require('../../../public/unirep_logo_white.png')}
className='absolute inset-0'
className="absolute inset-0"
variants={logoWhiteVariants}
initial='hidden'
animate='visible'
initial="hidden"
animate="visible"
/>
<motion.img
src={require('../../../public/comment.png')}
className='absolute inset-0'
className="absolute inset-0"
variants={commentVariants}
initial='hidden'
animate='visible'
initial="hidden"
animate="visible"
/>
<motion.img
src={require('../../../public/upvote.png')}
className='absolute inset-0'
className="absolute inset-0"
variants={upvoteVariants}
initial='hidden'
animate='visible'
initial="hidden"
animate="visible"
/>
<motion.img
src={require('../../../public/downvote.png')}
className='absolute inset-0'
className="absolute inset-0"
variants={downvoteVariants}
initial='hidden'
animate='visible'
initial="hidden"
animate="visible"
/>
</div>
<motion.h1
className='text-2xl text-neutral-200 font-semibold'
>
<motion.h1 className="text-2xl text-neutral-200 font-semibold">
Unirep Social TW
</motion.h1>
<motion.h2
className='mb-6 mt-9 text-sm font-light text-white text-center tracking-wider'
>
🙌🏻 Unirep Social TW <br /> 100%
<motion.h2 className="mb-6 mt-9 text-sm font-light text-white text-center tracking-wider">
🙌🏻 Unirep Social TW <br />
100%
</motion.h2>
</div>
</div>

View File

@@ -1,6 +1,6 @@
import React from 'react'
import { VscAccount } from 'react-icons/vsc'
import { useUser} from "../../contexts/User"
import { useUser } from '../../contexts/User'
const UserDropdown: React.FC = () => {
const { logout } = useUser()

View File

@@ -2,31 +2,34 @@ import React, { createContext, useState, useContext } from 'react'
export type LoadingStatus = 'loading' | 'success' | 'fail' | 'start'
type LoadingContextType = {
status: LoadingStatus
setStatus: React.Dispatch<React.SetStateAction<LoadingStatus>>
status: LoadingStatus
setStatus: React.Dispatch<React.SetStateAction<LoadingStatus>>
}
const defaultContextValue: LoadingContextType = {
status: 'start',
setStatus: () => {}
status: 'start',
setStatus: () => {},
}
export const LoadingContext = createContext<LoadingContextType>(defaultContextValue)
export const LoadingContext =
createContext<LoadingContextType>(defaultContextValue)
type LoadingProviderProps = {
children: React.ReactNode
children: React.ReactNode
}
export const LoadingProvider: React.FC<LoadingProviderProps> = ({ children }) => {
const [status, setStatus] = useState<LoadingStatus>('loading')
export const LoadingProvider: React.FC<LoadingProviderProps> = ({
children,
}) => {
const [status, setStatus] = useState<LoadingStatus>('loading')
return (
<LoadingContext.Provider value={{ status, setStatus }}>
{children}
</LoadingContext.Provider>
)
return (
<LoadingContext.Provider value={{ status, setStatus }}>
{children}
</LoadingContext.Provider>
)
}
export const useLoading = () => {
return useContext(LoadingContext)
return useContext(LoadingContext)
}

View File

@@ -1,4 +1,12 @@
import React, { createContext, useState, useEffect, useContext, ReactNode, useCallback, useMemo } from 'react'
import React, {
createContext,
useState,
useEffect,
useContext,
ReactNode,
useCallback,
useMemo,
} from 'react'
import { stringifyBigInts } from '@unirep/utils'
import { Identity } from '@semaphore-protocol/identity'
import { UserState } from '@unirep/core'
@@ -24,7 +32,7 @@ export interface UserContextType {
setProvableData: (provableData: bigint[]) => void
userState?: UserState
setUserState: (userState?: UserState) => void
provider: any // TODO: Replace with the appropriate type
provider: any // TODO: Replace with the appropriate type
setProvider: (provider: any) => void
signature: string
setSignature: (signature: string) => void
@@ -39,7 +47,10 @@ export interface UserContextType {
handleWalletSignMessage: () => Promise<void>
signup: () => Promise<void>
stateTransition: () => Promise<void>
requestData: (reqData: { [key: number]: string | number }, epkNonce: number) => Promise<void>
requestData: (
reqData: { [key: number]: string | number },
epkNonce: number
) => Promise<void>
proveData: (data: { [key: number]: string | number }) => Promise<any>
logout: () => void
}
@@ -56,14 +67,15 @@ interface UserProviderProps {
export const UserProvider: React.FC<UserProviderProps> = ({ children }) => {
const [currentEpoch, setCurrentEpoch] = useState<number>(0)
const [latestTransitionedEpoch, setLatestTransitionedEpoch] = useState<number>(0)
const [latestTransitionedEpoch, setLatestTransitionedEpoch] =
useState<number>(0)
const [isSignupLoading, setIsSignupLoading] = useState<boolean>(false)
const [fromServer, setFromServer] = useState<boolean>(false)
const [hasSignedUp, setHasSignedUp] = useState<boolean>(false)
const [data, setData] = useState<bigint[]>([])
const [provableData, setProvableData] = useState<bigint[]>([])
const [userState, setUserState] = useState<UserState | undefined>()
const [provider, setProvider] = useState<any>() // TODO: Replace with the appropriate type
const [provider, setProvider] = useState<any>() // TODO: Replace with the appropriate type
const [signature, setSignature] = useState<string>('')
const [hashUserId, setHashUserId] = useState<string>('')
@@ -90,15 +102,13 @@ export const UserProvider: React.FC<UserProviderProps> = ({ children }) => {
setProvider(providerInstance)
const userStateInstance = new UserState(
{
provider: providerInstance,
prover,
unirepAddress: UNIREP_ADDRESS,
attesterId: BigInt(APP_ADDRESS),
id: identity,
},
)
const userStateInstance = new UserState({
provider: providerInstance,
prover,
unirepAddress: UNIREP_ADDRESS,
attesterId: BigInt(APP_ADDRESS),
id: identity,
})
await userStateInstance.sync.start()
setUserState(userStateInstance)
@@ -113,15 +123,18 @@ export const UserProvider: React.FC<UserProviderProps> = ({ children }) => {
setLatestTransitionedEpoch(latestEpoch)
}
const loadData = useCallback(async (userState: UserState) => {
if (!userState) throw new Error('user state not initialized')
const loadData = useCallback(
async (userState: UserState) => {
if (!userState) throw new Error('user state not initialized')
const fetchedData = await userState.getData()
const fetchedProvableData = await userState.getProvableData()
const fetchedData = await userState.getData()
const fetchedProvableData = await userState.getProvableData()
setData(fetchedData)
setProvableData(fetchedProvableData)
}, [userState])
setData(fetchedData)
setProvableData(fetchedProvableData)
},
[userState]
)
const fieldCount = useMemo(() => {
return userState?.sync.settings.fieldCount
@@ -131,12 +144,15 @@ export const UserProvider: React.FC<UserProviderProps> = ({ children }) => {
return userState?.sync.settings.sumFieldCount
}, [userState])
const epochKey = useCallback((nonce: number) => {
if (!userState) return '0x'
const epoch = userState.sync.calcCurrentEpoch()
const key = userState.getEpochKeys(epoch, nonce)
return `0x${key.toString(16)}`
}, [userState])
const epochKey = useCallback(
(nonce: number) => {
if (!userState) return '0x'
const epoch = userState.sync.calcCurrentEpoch()
const key = userState.getEpochKeys(epoch, nonce)
return `0x${key.toString(16)}`
},
[userState]
)
const handleServerSignMessage = async () => {
const response = await fetch(`${SERVER}/api/identity`, {
@@ -146,7 +162,7 @@ export const UserProvider: React.FC<UserProviderProps> = ({ children }) => {
},
body: JSON.stringify({
hashUserId,
})
}),
})
if (!response.ok) {
throw new Error('False Identity')
@@ -158,15 +174,15 @@ export const UserProvider: React.FC<UserProviderProps> = ({ children }) => {
}
const handleWalletSignMessage = async () => {
const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' })
const accounts = await window.ethereum.request({
method: 'eth_requestAccounts',
})
const account = accounts[0]
const signature = await window.ethereum.request({
method: 'personal_sign',
params: [
ethers.utils.hexlify(
ethers.utils.toUtf8Bytes(hashUserId)
),
ethers.utils.hexlify(ethers.utils.toUtf8Bytes(hashUserId)),
account,
],
})
@@ -177,8 +193,10 @@ export const UserProvider: React.FC<UserProviderProps> = ({ children }) => {
const signup = useCallback(async () => {
if (!userState) throw new Error('user state not initialized')
const signupProof = await userState.genUserSignUpProof()
const publicSignals = signupProof.publicSignals.map(item => item.toString())
const proof = signupProof.proof.map(item => item.toString())
const publicSignals = signupProof.publicSignals.map((item) =>
item.toString()
)
const proof = signupProof.proof.map((item) => item.toString())
const response = await fetch(`${SERVER}/api/signup`, {
method: 'POST',
@@ -230,77 +248,83 @@ export const UserProvider: React.FC<UserProviderProps> = ({ children }) => {
setLatestTransitionedEpoch(latestTransitionEpoch)
}
const requestData = useCallback(
async (
reqData: { [key: number]: string | number },
epkNonce: number
) => {
if (!userState) throw new Error('user state not initialized')
const requestData = useCallback(async (
reqData: { [key: number]: string | number },
epkNonce: number
) => {
if (!userState) throw new Error('user state not initialized')
const filteredReqData = Object.entries(reqData)
.filter(([_, value]) => value !== '')
.reduce((obj, [key, value]) => ({ ...obj, [key]: value }), {})
const filteredReqData = Object.entries(reqData)
.filter(([_, value]) => value !== '')
.reduce((obj, [key, value]) => ({ ...obj, [key]: value }), {})
if (Object.keys(filteredReqData).length === 0) {
throw new Error('No data in the attestation')
}
if (Object.keys(filteredReqData).length === 0) {
throw new Error('No data in the attestation')
}
const epochKeyProof = await userState.genEpochKeyProof({
nonce: epkNonce,
})
const response = await fetch(`${SERVER}/api/request`, {
method: 'POST',
headers: {
'content-type': 'application/json',
},
body: JSON.stringify(
stringifyBigInts({
reqData: filteredReqData,
publicSignals: epochKeyProof.publicSignals,
proof: epochKeyProof.proof,
})
),
})
const data = await response.json()
await provider.waitForTransaction(data.hash)
await userState.waitForSync()
await loadData(userState)
},
[userState, provider, loadData]
)
const epochKeyProof = await userState.genEpochKeyProof({
nonce: epkNonce,
})
const response = await fetch(`${SERVER}/api/request`, {
method: 'POST',
headers: {
'content-type': 'application/json',
},
body: JSON.stringify(
stringifyBigInts({
reqData: filteredReqData,
publicSignals: epochKeyProof.publicSignals,
proof: epochKeyProof.proof,
})
),
})
const data = await response.json()
await provider.waitForTransaction(data.hash)
await userState.waitForSync()
await loadData(userState)
}, [userState, provider, loadData])
const proveData = useCallback(async (data: { [key: number]: string | number }) => {
if (!userState) throw new Error('user state not initialized')
const epoch = await userState.sync.loadCurrentEpoch()
const stateTree = await userState.sync.genStateTree(epoch)
const index = await userState.latestStateTreeLeafIndex(epoch)
const stateTreeProof = stateTree.createProof(index)
const provableData = await userState.getProvableData()
const sumFieldCount = userState.sync.settings.sumFieldCount
const values = Array(sumFieldCount).fill(0)
for (let [key, value] of Object.entries(data)) {
values[Number(key)] = value
}
const attesterId = userState.sync.attesterId
const circuitInputs = stringifyBigInts({
identity_secret: userState.id.secret,
state_tree_indexes: stateTreeProof.pathIndices,
state_tree_elements: stateTreeProof.siblings,
data: provableData,
epoch: epoch,
attester_id: attesterId,
value: values,
})
const { publicSignals, proof } = await prover.genProofAndPublicSignals(
'dataProof',
circuitInputs
)
const dataProof = new DataProof(publicSignals, proof, prover)
const valid = await dataProof.verify()
return stringifyBigInts({
publicSignals: dataProof.publicSignals,
proof: dataProof.proof,
valid,
})
}, [userState])
const proveData = useCallback(
async (data: { [key: number]: string | number }) => {
if (!userState) throw new Error('user state not initialized')
const epoch = await userState.sync.loadCurrentEpoch()
const stateTree = await userState.sync.genStateTree(epoch)
const index = await userState.latestStateTreeLeafIndex(epoch)
const stateTreeProof = stateTree.createProof(index)
const provableData = await userState.getProvableData()
const sumFieldCount = userState.sync.settings.sumFieldCount
const values = Array(sumFieldCount).fill(0)
for (let [key, value] of Object.entries(data)) {
values[Number(key)] = value
}
const attesterId = userState.sync.attesterId
const circuitInputs = stringifyBigInts({
identity_secret: userState.id.secret,
state_tree_indexes: stateTreeProof.pathIndices,
state_tree_elements: stateTreeProof.siblings,
data: provableData,
epoch: epoch,
attester_id: attesterId,
value: values,
})
const { publicSignals, proof } =
await prover.genProofAndPublicSignals(
'dataProof',
circuitInputs
)
const dataProof = new DataProof(publicSignals, proof, prover)
const valid = await dataProof.verify()
return stringifyBigInts({
publicSignals: dataProof.publicSignals,
proof: dataProof.proof,
valid,
})
},
[userState]
)
const logout = () => {
setHasSignedUp(false)
@@ -311,7 +335,6 @@ export const UserProvider: React.FC<UserProviderProps> = ({ children }) => {
localStorage.removeItem('hashUserId')
}
const value: UserContextType = {
currentEpoch,
setCurrentEpoch,
@@ -346,7 +369,7 @@ export const UserProvider: React.FC<UserProviderProps> = ({ children }) => {
stateTransition,
requestData,
proveData,
logout
logout,
}
return <UserContext.Provider value={value}>{children}</UserContext.Provider>
@@ -360,4 +383,4 @@ export const useUser = (): UserContextType => {
throw new Error('useUser must be used within a UserProvider')
}
return context
}
}

View File

@@ -1,10 +1,10 @@
import { useEffect } from "react";
import { useEffect } from 'react'
// TODO: No need now
const useAutoNavigation = (
hashUserId: string | null,
status: string | null,
navigate: (path: string) => void,
hashUserId: string | null,
status: string | null,
navigate: (path: string) => void,
hasSignedUp: boolean,
isSignupLoading: boolean,
isLoading: boolean
@@ -13,13 +13,18 @@ const useAutoNavigation = (
if (!isLoading) {
if (!hasSignedUp && hashUserId) {
navigate(`/login?code=${hashUserId}&status=${status}`)
} else if (!hasSignedUp && !hashUserId && !status && !isSignupLoading) {
} else if (
!hasSignedUp &&
!hashUserId &&
!status &&
!isSignupLoading
) {
navigate('/login')
} else {
return
}
}
}, [hasSignedUp, hashUserId, status, isSignupLoading, isLoading]);
};
}, [hasSignedUp, hashUserId, status, isSignupLoading, isLoading])
}
export default useAutoNavigation;
export default useAutoNavigation

View File

@@ -1,16 +1,13 @@
import { useEffect } from 'react'
const useInitUser = (
load: () => Promise<void>,
hashUserId: string | null,
) => {
const useInitUser = (load: () => Promise<void>, hashUserId: string | null) => {
useEffect(() => {
const initUser = async () => {
try {
await load()
} catch (error) {
console.log(error)
}
}
}
if (hashUserId) {

View File

@@ -8,8 +8,7 @@ export default function usePosts() {
const randomNonce = () => Math.round(Math.random())
const create = async (content: string) => {
if (!userState)
throw new Error('user state not initialized')
if (!userState) throw new Error('user state not initialized')
if (
userState.sync.calcCurrentEpoch() !==

View File

@@ -2,7 +2,7 @@ const useSignupWithServer = (
navigate: (path: string) => void,
setIsSignupLoading: (loading: boolean) => void,
getServerSignMessage: () => Promise<void>,
signup: () => Promise<void>,
signup: () => Promise<void>
) => {
const signupWithServer = async () => {
try {
@@ -21,4 +21,4 @@ const useSignupWithServer = (
return signupWithServer
}
export default useSignupWithServer
export default useSignupWithServer

View File

@@ -8,7 +8,7 @@ const useSignupWithWallet = (
navigate: (path: string) => void,
setIsSignupLoading: (loading: boolean) => void,
handleWalletSignMessage: () => Promise<void>,
signup: () => Promise<void>,
signup: () => Promise<void>
) => {
const signUpWithWallet = async () => {
try {
@@ -20,9 +20,9 @@ const useSignupWithWallet = (
handleWalletSignMessage()
await signup()
console.log('has signed up')
} catch (error) {
} catch (error) {
console.error(error)
} finally {
} finally {
setIsSignupLoading(false)
}
}

View File

@@ -1,4 +1,4 @@
import { useCallback } from "react"
import { useCallback } from 'react'
const useTwitterVerify = (SERVER: string) => {
const handleTwitterVerify = useCallback(async () => {
@@ -13,4 +13,4 @@ const useTwitterVerify = (SERVER: string) => {
return handleTwitterVerify
}
export default useTwitterVerify
export default useTwitterVerify

View File

@@ -32,10 +32,10 @@ const BaseLayout = () => {
return (
<motion.div
className='h-full overflow-y-scroll'
className="h-full overflow-y-scroll"
variants={gradientVariants}
initial='animate'
animate='animate'
initial="animate"
animate="animate"
>
<Outlet />
</motion.div>

View File

@@ -64,74 +64,75 @@ const Login: React.FC = () => {
}, [])
return (
<div className='flex flex-col h-full items-center'>
<div className={clsx(
`z-40 h-full flex flex-col w-11/12`,
method === 'signup' ? 'gap-12' : 'justify-between'
)}>
<div className={clsx(`flex flex-col gap-12`, method === 'signup' && 'sm:flex hidden')}>
<div
className='pt-24 flex items-center flex-col justify-center'
>
<div className="flex flex-col h-full items-center">
<div
className={clsx(
`z-40 h-full flex flex-col w-11/12`,
method === 'signup' ? 'gap-12' : 'justify-between'
)}
>
<div
className={clsx(
`flex flex-col gap-12`,
method === 'signup' && 'sm:flex hidden'
)}
>
<div className="pt-24 flex items-center flex-col justify-center">
<motion.img
src={require('../../public/unirep_logo_white.png')}
alt='UniRep Logo'
className='w-[120px] mb-2'
alt="UniRep Logo"
className="w-[120px] mb-2"
variants={basicVarients}
initial='hidden'
animate='visible'
initial="hidden"
animate="visible"
/>
<motion.h1
className='text-2xl font-semibold text-neutral-200'
className="text-2xl font-semibold text-neutral-200"
variants={textVariants}
initial='hidden'
animate='visible'
initial="hidden"
animate="visible"
>
Unirep Social TW
</motion.h1>
<motion.h2
className='text-sm font-light tracking-wider text-center text-white mt-9'
className="text-sm font-light tracking-wider text-center text-white mt-9"
variants={textVariants}
initial='hidden'
animate='visible'
initial="hidden"
animate="visible"
>
🙌🏻 Unirep Social TW <br />
100%
</motion.h2>
</div>
{method === 'signup' &&
{method === 'signup' && (
<motion.div
className='flex justify-center'
className="flex justify-center"
variants={basicVarients}
initial='hidden'
animate='visible'
initial="hidden"
animate="visible"
>
{
<StepInfo
hashUserId={hashUserId}
/>
}
{<StepInfo hashUserId={hashUserId} />}
</motion.div>
}
)}
</div>
{method === 'signup' &&
<>
<div
className='absolute top-7 bg-[#E8ECF4] p-3 sm:px-4 sm:py-2 rounded-lg cursor-pointer flex justify-center items-center'
onClick={handleBack}
>
<IoChevronBack
size={16}
/>
<span className='sm:block hidden mx-2 text-sm font-bold'></span>
</div>
<div className='sm:hidden flex flex-col text-white font-semibold text-2xl tracking-wider mt-40'>
<p></p>
<p>Unirep Social TW</p>
{hashUserId && <p></p>}
</div>
</>
}
{method === 'signup' && (
<>
<div
className="absolute top-7 bg-[#E8ECF4] p-3 sm:px-4 sm:py-2 rounded-lg cursor-pointer flex justify-center items-center"
onClick={handleBack}
>
<IoChevronBack size={16} />
<span className="sm:block hidden mx-2 text-sm font-bold">
</span>
</div>
<div className="sm:hidden flex flex-col text-white font-semibold text-2xl tracking-wider mt-40">
<p></p>
<p>Unirep Social TW</p>
{hashUserId && <p></p>}
</div>
</>
)}
<AuthForm
hashUserId={hashUserId}
method={method}
@@ -139,18 +140,16 @@ const Login: React.FC = () => {
onLogin={() => setMethod('login')}
/>
</div>
{method === ''
&&
{method === '' && (
<motion.div
className='fixed inset-0 z-30 overflow-y-none mt-[220px]'
className="fixed inset-0 z-30 overflow-y-none mt-[220px]"
variants={postListVariants}
initial='start'
animate='end'
initial="start"
animate="end"
>
<DemoPostList />
</motion.div>
}
)}
</div>
)
}

View File

@@ -19,9 +19,6 @@
"useDefineForClassFields": true,
"outDir": "build"
},
"include": [
"src",
"../../node_modules/ts-jest/globals.d.ts"
],
"include": ["src", "../../node_modules/ts-jest/globals.d.ts"],
"exclude": ["node_modules", "typings", "build/**/*"]
}

1828
yarn.lock

File diff suppressed because it is too large Load Diff