From b6145ce0f47a19214df07b3b256e49b7732c20f9 Mon Sep 17 00:00:00 2001 From: Shubham-tiwari123 Date: Tue, 2 Feb 2021 16:52:44 +0530 Subject: [PATCH 1/7] adds function to update user profile --- .../middleware/models/UserRegistration.js | 7 ++++ packages/react-app/src/App.jsx | 2 +- packages/react-app/src/components/Profile.js | 34 ++++++++++++++++- .../react-app/src/components/auth/SignUp.js | 3 +- packages/react-app/src/lib/threadDb.js | 37 +++++++++++++++++-- 5 files changed, 75 insertions(+), 8 deletions(-) diff --git a/packages/middleware/models/UserRegistration.js b/packages/middleware/models/UserRegistration.js index fb58a41..6a69e77 100644 --- a/packages/middleware/models/UserRegistration.js +++ b/packages/middleware/models/UserRegistration.js @@ -7,6 +7,13 @@ const UserRegistration = { did: {type:'string'}, name: {type: 'string'}, email: {type: 'string'}, + profileDetails: { + type: 'object', + properties: { + DOB: {type: 'string'}, + phoneNumber: {type:'string'} + } + }, address: { type: 'string'}, publicKey: { type: 'string'}, userType: { type: 'number'}, diff --git a/packages/react-app/src/App.jsx b/packages/react-app/src/App.jsx index 38ba7a7..ec6ce7c 100644 --- a/packages/react-app/src/App.jsx +++ b/packages/react-app/src/App.jsx @@ -82,7 +82,7 @@ function App() { const client = await loginUserWithChallenge(identity); let userInfo if (client !== null) { - userInfo = await getLoginUser(user.address, idx) + userInfo = await getLoginUser(user.address) if (userInfo !== null) { localStorage.setItem("USER", JSON.stringify(userInfo)) localStorage.setItem("password", "12345"); diff --git a/packages/react-app/src/components/Profile.js b/packages/react-app/src/components/Profile.js index 402f9fe..88b30a2 100644 --- a/packages/react-app/src/components/Profile.js +++ b/packages/react-app/src/components/Profile.js @@ -4,21 +4,48 @@ import {FieldTimeOutlined, MailOutlined, UserOutlined} from "@ant-design/icons"; import {definitions} from "../ceramic/config.json"; import {Header, Icon, Loader, Segment} from "semantic-ui-react"; import {ProfileContainer} from "./styles/Profile.Style"; +import {updateUserProfile} from "../lib/threadDb"; export default function Profile({ ceramic, idx }) { const [user, setUser] = useState(null); + const [name, setName] = useState(''); + const [email, setEmail] = useState(''); + const [dob, setDob] = useState(''); + const [userId, setUserId] = useState(''); + const [phoneNumber, setPhoneNumber] = useState(''); + + const userType = { party: 0, notary: 1 }; + const [userLoading, setUserLoading] = useState(true); useEffect(() => { async function getUserData() { try { if (idx) { const data = await idx.get(definitions.profile, idx.id); - setUser(data); + + const userThreadDb = JSON.parse(localStorage.getItem('USER')) + setUser(userThreadDb); + setName(userThreadDb.name); + setEmail(userThreadDb.email); + setDob(userThreadDb.profileDetails.DOB); + setPhoneNumber(userThreadDb.profileDetails.phoneNumber) + setUserId(userThreadDb._id) setUserLoading(false); if(data){ console.log("data fetched") }else{ + // Registration on idx console.log("Something is wrong with IDX") + let notary = true + if (userThreadDb.userType===0){ + notary = false + } + await idx.set(definitions.profile, { + name: userThreadDb.name, + email: userThreadDb.email, + notary: notary, + userAddress: userThreadDb.address + }); } } } catch (err) { @@ -28,6 +55,11 @@ export default function Profile({ ceramic, idx }) { getUserData(); }, [idx]); + + const updateProfile = async ()=>{ + await updateUserProfile(name, email, dob, phoneNumber, userId, idx) + } + return !userLoading ? ( user ? <> diff --git a/packages/react-app/src/components/auth/SignUp.js b/packages/react-app/src/components/auth/SignUp.js index efe95fe..50ce07e 100644 --- a/packages/react-app/src/components/auth/SignUp.js +++ b/packages/react-app/src/components/auth/SignUp.js @@ -12,7 +12,7 @@ function SignUp({ authStatus, setUserStatus, identity, address, idx, seed }) { const [open, setOpen] = useState(true); const [name, setName] = useState(""); - const [email, setEmail] = useState(""); + const [email, setEmail] = useState("NA"); const [notary, setNotary] = useState(false); const [error, setError] = useState({status: false, message: ''}); @@ -47,7 +47,6 @@ function SignUp({ authStatus, setUserStatus, identity, address, idx, seed }) { name: name, email: email, notary: notary, - joindate : moment(new Date()).format("ll"), userAddress: address }); } diff --git a/packages/react-app/src/lib/threadDb.js b/packages/react-app/src/lib/threadDb.js index 6095adb..98db37f 100644 --- a/packages/react-app/src/lib/threadDb.js +++ b/packages/react-app/src/lib/threadDb.js @@ -5,7 +5,7 @@ const { Client, Where, ThreadID } = require('@textile/hub') const wallet = require('wallet-besu') const ethers = require('ethers') const io = require('socket.io-client'); - +const {definitions} = require('../ceramic/config.json') export const registerNewUser = async function(did, name, email, privateKey, userType, address){ try { @@ -17,6 +17,10 @@ export const registerNewUser = async function(did, name, email, privateKey, user did:did, name: name, email: email, + profileDetails:{ + DOB: 'NA', + phoneNumber: 'NA' + }, address: address, publicKey: publicKey.toString("hex"), userType: userType, @@ -101,14 +105,12 @@ export const getCredentials = async function(){ return {client, threadDb} } -export const getLoginUser = async function(address, idx){ +export const getLoginUser = async function(address){ try { const {threadDb, client} = await getCredentials() const query = new Where('address').eq(address) const threadId = ThreadID.fromBytes(threadDb) const result = await client.find(threadId, 'RegisterUser', query) - // By passing Ceramic IDX profile check - // const ceramicResult = await idx.get(definitions.profile, idx.id) if (result.length<1){ console.log("Please register user!") return null @@ -477,4 +479,31 @@ export const downloadFiles = async function (name, key, loggedUser,documentLocat }) } +export const updateUserProfile = async function(name, email, dob, phoneNumber,userId, idx){ + const {threadDb, client} = await getCredentials() + const threadId = ThreadID.fromBytes(threadDb) + const user = await client.findByID(threadId, 'RegisterUser', userId) + + if (user.length === 1){ + user[0].name = name + user[0].email = email + user[0].profileDetails.DOB = dob + user[0].profileDetails.phoneNumber = phoneNumber + + await client.save(threadId,'RegisterUser',[user[0]]) + + let notary = true; + if (user[0].userType ===0) { + notary = false; + } + + await idx.set(definitions.profile, { + name: name, + email: email, + notary: notary, + userAddress: user[0].address + }); + } + +} From 8d924009aed58d7273bebcf18003c3f7092d8817 Mon Sep 17 00:00:00 2001 From: koushith Date: Wed, 3 Feb 2021 11:03:40 +0530 Subject: [PATCH 2/7] adds profile edit feature --- packages/contracts/src/config/config.json | 6 +- packages/react-app/src/App.jsx | 2 +- packages/react-app/src/ceramic/config.json | 2 +- packages/react-app/src/components/Profile.js | 75 ----------- .../components/Profile/EditProfile.Styles.js | 42 ++++++ .../src/components/Profile/EditProfile.js | 65 ++++++++++ .../src/components/Profile/Profile.js | 121 ++++++++++++++++++ .../react-app/src/components/auth/SignUp.js | 54 ++++---- .../src/components/styles/Profile.Style.js | 15 ++- .../src/contracts/DocumentRegistry.address.js | 2 +- .../src/contracts/Signchain.address.js | 2 +- .../src/contracts/SigningModule.address.js | 2 +- 12 files changed, 276 insertions(+), 112 deletions(-) delete mode 100644 packages/react-app/src/components/Profile.js create mode 100644 packages/react-app/src/components/Profile/EditProfile.Styles.js create mode 100644 packages/react-app/src/components/Profile/EditProfile.js create mode 100644 packages/react-app/src/components/Profile/Profile.js diff --git a/packages/contracts/src/config/config.json b/packages/contracts/src/config/config.json index a6561b8..1d26e44 100644 --- a/packages/contracts/src/config/config.json +++ b/packages/contracts/src/config/config.json @@ -1,5 +1,5 @@ { - "DocumentRegistryAddress": "0xBF5f700E437474ad78a1a244e3625C8453Db72C0", - "SignchainAddress": "0x2b5De22765A433601eF480f4a88A01B36f127092", - "SigningModuleAddress": "0x9032b75FDA26E678cB4B51C9Ef0d2AD8AeaB651E" + "DocumentRegistryAddress": "0x414D48239f7e610e63D0d968b29d47fC823c89aA", + "SignchainAddress": "0xf27276e9fb701D28d91De7666847FD40e5E07EAf", + "SigningModuleAddress": "0x62d4AE524625e95D2d9B16EdB82b601d20E564DF" } \ No newline at end of file diff --git a/packages/react-app/src/App.jsx b/packages/react-app/src/App.jsx index 38ba7a7..8a001a3 100644 --- a/packages/react-app/src/App.jsx +++ b/packages/react-app/src/App.jsx @@ -15,7 +15,7 @@ import {definitions} from "./ceramic/config.json" import Dashboard from "./components/Dashboard"; import Documents from "./components/Documents"; -import Profile from "./components/Profile"; +import Profile from "./components/Profile/Profile"; import Layout from "./components/Layout"; import Steps from './components/Stepper/Steps' import Verify from './components/Verify/Verify' diff --git a/packages/react-app/src/ceramic/config.json b/packages/react-app/src/ceramic/config.json index dac40c6..4b36277 100644 --- a/packages/react-app/src/ceramic/config.json +++ b/packages/react-app/src/ceramic/config.json @@ -1 +1 @@ -{"definitions":{"profile":"kjzl6cwe1jw146v7h1v7cfvwsxstt7953pc0umz8pk3scteb5y1pogp8csdijkp"},"schemas":{"profile":"ceramic://k3y52l7qbv1frxwsl4qlm6vvmeyc13s9czadawd7jmsb4pymgle3h2f3r2n20pclc"}} \ No newline at end of file +{"definitions":{"profile":"kjzl6cwe1jw148ha2ha9dz9btt8zdmdkdcu8v8kzd2kz7kwv0hfqfudiz8r8e2w"},"schemas":{"profile":"ceramic://k3y52l7qbv1frymlhyz3dom8wex9qgrfokf4l3rtp0y168cb7b8nl9241zvghqolc"}} \ No newline at end of file diff --git a/packages/react-app/src/components/Profile.js b/packages/react-app/src/components/Profile.js deleted file mode 100644 index 402f9fe..0000000 --- a/packages/react-app/src/components/Profile.js +++ /dev/null @@ -1,75 +0,0 @@ -// /* eslint-disable */ -import React, {useEffect, useState} from "react"; -import {FieldTimeOutlined, MailOutlined, UserOutlined} from "@ant-design/icons"; -import {definitions} from "../ceramic/config.json"; -import {Header, Icon, Loader, Segment} from "semantic-ui-react"; -import {ProfileContainer} from "./styles/Profile.Style"; - -export default function Profile({ ceramic, idx }) { - const [user, setUser] = useState(null); - const [userLoading, setUserLoading] = useState(true); - useEffect(() => { - async function getUserData() { - try { - if (idx) { - const data = await idx.get(definitions.profile, idx.id); - setUser(data); - setUserLoading(false); - if(data){ - console.log("data fetched") - }else{ - console.log("Something is wrong with IDX") - } - } - } catch (err) { - console.log(err); - } - } - getUserData(); - }, [idx]); - - return !userLoading ? ( - user ? - <> - -
-
- -

{user.name}

-

- {idx.id}{" "} -

-

- {user.userAddress}{" "} -

-
-
- {user.notary ? "Notary" : "Party"} -
-
- - {user.email} -
-
- {user.joindate} -
-
-
-
-
- : - -
- - No profile found :(. -
- - There was an issue fetching the user profile. - -
- ) : ( - - Fetching profile - - ); -} diff --git a/packages/react-app/src/components/Profile/EditProfile.Styles.js b/packages/react-app/src/components/Profile/EditProfile.Styles.js new file mode 100644 index 0000000..f0abb7a --- /dev/null +++ b/packages/react-app/src/components/Profile/EditProfile.Styles.js @@ -0,0 +1,42 @@ +import styled from "styled-components"; + +export const FormContainer = styled.div` + overflow: hidden; + width: 392px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + margin-bottom: 20px; + .logo-container { + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 15px; + } + .form-input { + margin: 12px 0 12px 0; + width: 392px; + height: 37.8px !important; + width: 100%; + } + .checkbox { + color: #717171; + margin-top: 14px; + margin-bottom: 2px; + } + /* .btn-primary { + width: 374px !important; + height: 38px !important; + background-color: #4c51bf; + color: #fff; + margin-right: 1px; + } */ + + .form-input-btn { + width: 382px; + color: #fff; + background-color: #4c51bf; + margin-left: 12px; + } +`; diff --git a/packages/react-app/src/components/Profile/EditProfile.js b/packages/react-app/src/components/Profile/EditProfile.js new file mode 100644 index 0000000..91e69d9 --- /dev/null +++ b/packages/react-app/src/components/Profile/EditProfile.js @@ -0,0 +1,65 @@ +import React, { useEffect, useState } from "react"; +import { Button, Checkbox, Form, Input, Message, Modal } from "semantic-ui-react"; + +import { FormContainer } from "./EditProfile.Styles"; + +function EditProfile({ open, setOpen }) { + const [name, setName] = useState(""); + const [email, setEmail] = useState(""); + const [notary, setNotary] = useState(false); + const [error, setError] = useState({ status: false, message: "" }); + + const SignupStatus = { preInit: 0, init: 1, wallet: 2, ceramic: 3, contract: 4 }; + const [signupStatus, setSignupStatus] = useState(SignupStatus.preInit); + const userType = { party: 0, notary: 1 }; + + return ( + <> + setOpen(false)} + onOpen={() => setOpen(true)} + size="small" + style={{ width: "450px" }} + > + Please provide these details + + + +
+ + setName(e.target.value)} + /> + + + + setEmail(e.target.value)} + /> + + + +
+
+
+
+
+ + ); +} + +export default EditProfile; diff --git a/packages/react-app/src/components/Profile/Profile.js b/packages/react-app/src/components/Profile/Profile.js new file mode 100644 index 0000000..50c6661 --- /dev/null +++ b/packages/react-app/src/components/Profile/Profile.js @@ -0,0 +1,121 @@ +// /* eslint-disable */ +import React, { useEffect, useState } from "react"; + +import { definitions } from "../../ceramic/config.json"; +import { Header, Icon, Loader, Segment, Card, Table, Button } from "semantic-ui-react"; +import EditProfile from "./EditProfile"; +import { ProfileContainer } from "../styles/Profile.Style"; + +export default function Profile({ ceramic, idx }) { + const [open, setOpen] = useState(false); + const [user, setUser] = useState(null); + const [userLoading, setUserLoading] = useState(true); + const [name, setName] = useState(""); + const [email, setEmail] = useState(""); + const [dob, setDob] = useState(""); + const [userId, setUserId] = useState(""); + const [phoneNumber, setPhoneNumber] = useState(""); + + useEffect(() => { + async function getUserData() { + try { + if (idx) { + const data = await idx.get(definitions.profile, idx.id); + setUser(data); + setUserLoading(false); + if (data) { + console.log("data fetched"); + } else { + console.log("Something is wrong with IDX"); + } + } + } catch (err) { + console.log(err); + } + } + getUserData(); + }, [idx]); + + return !userLoading ? ( + user ? ( + <> + + +
+
+ +

{user.name}

+

+ {idx.id}{" "} +

+

+ {user.userAddress}{" "} +

+ +
+
+ + + + + + + + + + Type + + {user.notary ? "Notary" : "Party"} + + + + + {" "} + + Email + + {user.email} + + + + {" "} + + Organistion + + Infosys + + + + + + Member Since + + {user.joindate} + + +
+ +
+
+
+
+
+
+ + ) : ( + +
+ + No profile found :(. +
+ There was an issue fetching the user profile. +
+ ) + ) : ( + + Fetching profile + + ); +} diff --git a/packages/react-app/src/components/auth/SignUp.js b/packages/react-app/src/components/auth/SignUp.js index efe95fe..78b1b93 100644 --- a/packages/react-app/src/components/auth/SignUp.js +++ b/packages/react-app/src/components/auth/SignUp.js @@ -1,9 +1,9 @@ -import React, {useEffect, useState} from "react"; -import {Button, Checkbox, Form, Input, Message, Modal} from "semantic-ui-react"; +import React, { useEffect, useState } from "react"; +import { Button, Checkbox, Form, Input, Message, Modal } from "semantic-ui-react"; import logo from "../../images/logoInverted.png"; -import {definitions} from "../../ceramic/config.json"; -import {FormContainer} from "../styles/SignUp.Styles"; -import {loginUserWithChallenge, registerNewUser} from "../../lib/threadDb"; +import { definitions } from "../../ceramic/config.json"; +import { FormContainer } from "../styles/SignUp.Styles"; +import { loginUserWithChallenge, registerNewUser } from "../../lib/threadDb"; const index = require("../../lib/e2ee.js"); const moment = require("moment"); @@ -14,7 +14,7 @@ function SignUp({ authStatus, setUserStatus, identity, address, idx, seed }) { const [name, setName] = useState(""); const [email, setEmail] = useState(""); const [notary, setNotary] = useState(false); - const [error, setError] = useState({status: false, message: ''}); + const [error, setError] = useState({ status: false, message: "" }); const SignupStatus = { preInit: 0, init: 1, wallet: 2, ceramic: 3, contract: 4 }; const [signupStatus, setSignupStatus] = useState(SignupStatus.preInit); @@ -43,17 +43,15 @@ function SignUp({ authStatus, setUserStatus, identity, address, idx, seed }) { const accounts = await index.getAllAccounts(pass); setSignupStatus(SignupStatus.ceramic); try { - await idx.set(definitions.profile, { - name: name, - email: email, - notary: notary, - joindate : moment(new Date()).format("ll"), - userAddress: address - }); - } - catch(e) { - console.log("Failed to create profile on IDX") - + await idx.set(definitions.profile, { + name: name, + email: email, + notary: notary, + joindate: moment(new Date()).format("ll"), + userAddress: address, + }); + } catch (e) { + console.log("Failed to create profile on IDX"); } setSignupStatus(SignupStatus.contract); //const dbClient = await authorizeUser(password) @@ -65,13 +63,13 @@ function SignUp({ authStatus, setUserStatus, identity, address, idx, seed }) { email, accounts[0], notary ? userType.notary : userType.party, - address + address, ); if (registrationStatus) { setUserStatus(authStatus.loggedIn); } else { localStorage.clear(); - setError({status: true, message: 'An account with same email/ wallet address exists'}) + setError({ status: true, message: "An account with same email/ wallet address exists" }); setSignupStatus(SignupStatus.init); } } @@ -107,12 +105,12 @@ function SignUp({ authStatus, setUserStatus, identity, address, idx, seed }) { /> - + setEmail(e.target.value)} /> @@ -128,15 +126,15 @@ function SignUp({ authStatus, setUserStatus, identity, address, idx, seed }) { setNotary(!notary); }} /> - { - error.status ? - Account creation failed -

{error.message}

-
: null - } + {error.status ? ( + + Account creation failed +

{error.message}

+
+ ) : null} {signupStatus == SignupStatus.init ? ( - ) : signupStatus == SignupStatus.wallet ? ( diff --git a/packages/react-app/src/components/styles/Profile.Style.js b/packages/react-app/src/components/styles/Profile.Style.js index 581cb05..aa248a3 100644 --- a/packages/react-app/src/components/styles/Profile.Style.js +++ b/packages/react-app/src/components/styles/Profile.Style.js @@ -5,7 +5,7 @@ export const ProfileContainer = styled.div` justify-content: center; background-color: #f0f2f5; width: 100%; - height: 80vh; + /* height: 80vh; */ border-radius: 4px; .profile { align-items: center; @@ -35,4 +35,17 @@ export const ProfileContainer = styled.div` grid-template-columns: repeat(3, 1fr); margin-top: 40px; } + .meta-info { + display: flex; + margin: auto; + justify-content: center; + } + .ui.card > .content { + text-align: inherit; + } + .about-card { + width: 700px; + margin-right: 18px; + overflow: hidden; + } `; diff --git a/packages/react-app/src/contracts/DocumentRegistry.address.js b/packages/react-app/src/contracts/DocumentRegistry.address.js index 59d0266..77fbc6e 100644 --- a/packages/react-app/src/contracts/DocumentRegistry.address.js +++ b/packages/react-app/src/contracts/DocumentRegistry.address.js @@ -1 +1 @@ -module.exports = "0xBF5f700E437474ad78a1a244e3625C8453Db72C0"; \ No newline at end of file +module.exports = "0x414D48239f7e610e63D0d968b29d47fC823c89aA"; \ No newline at end of file diff --git a/packages/react-app/src/contracts/Signchain.address.js b/packages/react-app/src/contracts/Signchain.address.js index beebc67..098f6f7 100644 --- a/packages/react-app/src/contracts/Signchain.address.js +++ b/packages/react-app/src/contracts/Signchain.address.js @@ -1 +1 @@ -module.exports = "0x2b5De22765A433601eF480f4a88A01B36f127092"; \ No newline at end of file +module.exports = "0xf27276e9fb701D28d91De7666847FD40e5E07EAf"; \ No newline at end of file diff --git a/packages/react-app/src/contracts/SigningModule.address.js b/packages/react-app/src/contracts/SigningModule.address.js index 2b9da74..4e1a775 100644 --- a/packages/react-app/src/contracts/SigningModule.address.js +++ b/packages/react-app/src/contracts/SigningModule.address.js @@ -1 +1 @@ -module.exports = "0x9032b75FDA26E678cB4B51C9Ef0d2AD8AeaB651E"; \ No newline at end of file +module.exports = "0x62d4AE524625e95D2d9B16EdB82b601d20E564DF"; \ No newline at end of file From 0313dc9cb0cac3ff50434b7462b3d1ac939ed6cb Mon Sep 17 00:00:00 2001 From: Shubham-tiwari123 Date: Wed, 3 Feb 2021 16:36:59 +0530 Subject: [PATCH 3/7] integrates user-profile update function --- packages/react-app/src/App.jsx | 4 --- .../src/components/Profile/EditProfile.js | 22 +++++++----- .../src/components/Profile/Profile.js | 36 +++++++++++++------ packages/react-app/src/lib/threadDb.js | 9 +++-- 4 files changed, 45 insertions(+), 26 deletions(-) diff --git a/packages/react-app/src/App.jsx b/packages/react-app/src/App.jsx index e47fae9..a796097 100644 --- a/packages/react-app/src/App.jsx +++ b/packages/react-app/src/App.jsx @@ -70,10 +70,6 @@ function App() { setInjectedProvider(new Web3Provider(provider)); }, [setInjectedProvider]); - async function test (seed, identity, idx){ - - } - async function loginUser(seed, identity, idx, address) { const pass = Buffer.from(new Uint8Array(seed)).toString("hex") const user = JSON.parse(localStorage.getItem('USER')) diff --git a/packages/react-app/src/components/Profile/EditProfile.js b/packages/react-app/src/components/Profile/EditProfile.js index 9d1e40e..c9975a2 100644 --- a/packages/react-app/src/components/Profile/EditProfile.js +++ b/packages/react-app/src/components/Profile/EditProfile.js @@ -2,15 +2,20 @@ import React, { useEffect, useState } from "react"; import { Button, Checkbox, Form, Input, Message, Modal } from "semantic-ui-react"; import { FormContainer } from "./EditProfile.Styles"; +import {updateUserProfile} from "../../lib/threadDb"; -function EditProfile({ open, setOpen }) { - const [name, setName] = useState(""); - const [email, setEmail] = useState(""); +function EditProfile({ open, setOpen, user, idx }) { + const [name, setName] = useState(user.name); + const [email, setEmail] = useState(user.email); - const [dob, setDob] = useState(""); - const [userId, setUserId] = useState(""); - const [phoneNumber, setPhoneNumber] = useState(""); - const [Type, setType] = useState("Party"); + const [dob, setDob] = useState(user.profileDetails.DOB); + const [userId, setUserId] = useState(user._id); + const [phoneNumber, setPhoneNumber] = useState(user.profileDetails.phoneNumber); + + const updateProfile = async ()=>{ + console.log("Function called!!!") + await updateUserProfile(name, email, dob, phoneNumber, userId, idx, user.publicKey) + } return ( <> @@ -43,7 +48,6 @@ function EditProfile({ open, setOpen }) { fluid type="email" icon="mail" - pattern=".+@globex.com" size="30" iconPosition="left" placeholder="JohnDoe@domain.com" @@ -78,7 +82,7 @@ function EditProfile({ open, setOpen }) { />
- diff --git a/packages/react-app/src/components/Profile/Profile.js b/packages/react-app/src/components/Profile/Profile.js index 330f983..687f3ea 100644 --- a/packages/react-app/src/components/Profile/Profile.js +++ b/packages/react-app/src/components/Profile/Profile.js @@ -16,12 +16,26 @@ export default function Profile({ ceramic, idx }) { try { if (idx) { const data = await idx.get(definitions.profile, idx.id); - setUser(data); + + const userThreadDb = JSON.parse(localStorage.getItem('USER')) + setUser(userThreadDb); setUserLoading(false); - if (data) { - console.log("data fetched"); - } else { - console.log("Something is wrong with IDX"); + if(data){ + console.log("data fetched") + console.log("Data:", data) + }else{ + // Registration on idx + console.log("Something is wrong with IDX") + let notary = true + if (userThreadDb.userType===0){ + notary = false + } + await idx.set(definitions.profile, { + name: userThreadDb.name, + email: userThreadDb.email, + notary: notary, + userAddress: userThreadDb.address + }); } } } catch (err) { @@ -34,7 +48,7 @@ export default function Profile({ ceramic, idx }) { return !userLoading ? ( user ? ( <> - +
@@ -44,7 +58,7 @@ export default function Profile({ ceramic, idx }) { {idx.id}{" "}

- {user.userAddress}{" "} + {user.address}{" "}

@@ -77,7 +91,7 @@ export default function Profile({ ceramic, idx }) { Phone - 9999999999 + {user.profileDetails.phoneNumber} @@ -85,16 +99,16 @@ export default function Profile({ ceramic, idx }) { DOB - 14-12-1997 + {user.profileDetails.DOB} - + {/* Member Since {user.joindate} - + */} diff --git a/packages/react-app/src/components/Profile/Warning.js b/packages/react-app/src/components/Profile/Warning.js new file mode 100644 index 0000000..c5ebf31 --- /dev/null +++ b/packages/react-app/src/components/Profile/Warning.js @@ -0,0 +1,20 @@ +import React from "react"; +import { Button, Icon, Modal } from "semantic-ui-react"; + +function Warning({ warning, setWarning }) { + return ( + setWarning(true)} onClick={() => setWarning(false)}> + OOPS!! + +

Invalid Email/Phone format.

+
+ + + +
+ ); +} + +export default Warning; diff --git a/packages/react-app/src/components/Profile/updateSuccess.js b/packages/react-app/src/components/Profile/updateSuccess.js new file mode 100644 index 0000000..f397258 --- /dev/null +++ b/packages/react-app/src/components/Profile/updateSuccess.js @@ -0,0 +1,20 @@ +import React from "react"; +import { Button, Icon, Modal } from "semantic-ui-react"; + +function updateSuccess({ success, setSuccess }) { + return ( + setSuccess(true)} onClick={() => setSuccess(false)}> + OOPS!! + +

Invalid Email/Phone format.

+
+ + + +
+ ); +} + +export default updateSuccess; From 2feb3b6ab46a3f31a8b6533775042f54be42d6a1 Mon Sep 17 00:00:00 2001 From: yathishram <123yathish.r@gmail.com> Date: Mon, 8 Feb 2021 17:34:49 +0530 Subject: [PATCH 7/7] updates ceramic schemas --- packages/middleware/services/email/sgEmail.js | 29 +++++++++++++++-- .../services/email/templates/signDocument.js | 31 +++++++++++++++++++ packages/react-app/src/App.jsx | 7 +++-- packages/react-app/src/ceramic/bootstrap.js | 12 ++++++- packages/react-app/src/ceramic/config.json | 2 +- .../components/Documents/DocumentDetails.js | 4 +++ .../src/components/Profile/EditProfile.js | 6 ++-- .../src/components/Profile/Profile.js | 24 ++++++++------ .../react-app/src/components/auth/SignUp.js | 2 ++ packages/react-app/src/lib/notifications.js | 14 ++++++++- packages/react-app/src/lib/threadDb.js | 11 +++++-- 11 files changed, 120 insertions(+), 22 deletions(-) create mode 100644 packages/middleware/services/email/templates/signDocument.js diff --git a/packages/middleware/services/email/sgEmail.js b/packages/middleware/services/email/sgEmail.js index 031fcfd..e63b38d 100644 --- a/packages/middleware/services/email/sgEmail.js +++ b/packages/middleware/services/email/sgEmail.js @@ -1,6 +1,6 @@ const sgMail = require('@sendgrid/mail'); const sendDocTemplate = require('./templates/sendDocument'); - +const signedDocTemplate = require('./templates/signDocument') module.exports = (app) => { @@ -25,6 +25,31 @@ module.exports = (app) => { }) res.send(JSON.stringify({status: true, msg: "Email sent successfully"})) }) + + + app.post('/email/sign', async (req, res) =>{ + + sgMail.setApiKey(process.env.SENDGRID_API_KEY) + + const msg = { + to: req.body.recipients, // Change to your recipient + from: 'signchain@consensolabs.com', + subject: 'Signchain - Your document is signed', + html: signedDocTemplate(req.body.data.sender, req.body.data.docId), + } + sgMail + .send(msg) + .then(() => { + console.log('Email sent') + }) + .catch((error) => { + console.error(error) + }) + res.send(JSON.stringify({status: true, msg: "Email sent successfully"})) + }) + -} \ No newline at end of file +} + + diff --git a/packages/middleware/services/email/templates/signDocument.js b/packages/middleware/services/email/templates/signDocument.js new file mode 100644 index 0000000..d275070 --- /dev/null +++ b/packages/middleware/services/email/templates/signDocument.js @@ -0,0 +1,31 @@ +module.exports = (signer, documentId) => { +return ( + `New email
+
+

+ View in browser

+
+
+ +

Document has been signed by a counter party

Review the document

+
+

Hey there,

${signer} has signed a document on Signchain that was shared by you. You can review the document now.

+ Review
+
+

Check out all the other documents that are shared by you and needs to be signed by going to the Documents section.

+ All documents
+
+
+
+ `); +} \ No newline at end of file diff --git a/packages/react-app/src/App.jsx b/packages/react-app/src/App.jsx index a796097..3727ee7 100644 --- a/packages/react-app/src/App.jsx +++ b/packages/react-app/src/App.jsx @@ -35,7 +35,7 @@ import NetworkChange from './components/warnings/NetworkChange' import DocumentDetails from './components/Documents/DocumentDetails' const blockExplorer = "https://etherscan.io/" -const CERAMIC_URL = 'https://ceramic-clay.3boxlabs.com' +const CERAMIC_URL = 'https://ceramic.signchain.xyz' const mainnetProvider = getDefaultProvider("mainnet", { infura: INFURA_ID, etherscan: ETHERSCAN_KEY, quorum: 1 }) function App() { @@ -47,7 +47,7 @@ function App() { const [userStatus, setUserStatus] = useState(0); const [seed, setSeed] = useState([]) const [connectLoading, setConnectLoading] = useState(false) - + const [network, setNetwork] = useState(null); const authStatus = { "disconnected" : 0, "connected" : 1, @@ -104,6 +104,9 @@ function App() { setConnectLoading(true) await loadWeb3Modal() const {seed, metamask} = await generateSignature(); + if(metamask){ + setNetwork(metamask.signer.provider._network.name) + } setSeed(seed) const identity = PrivateKey.fromRawEd25519Seed(Uint8Array.from(seed)) setIdentity(identity) diff --git a/packages/react-app/src/ceramic/bootstrap.js b/packages/react-app/src/ceramic/bootstrap.js index d2a1380..e756a50 100644 --- a/packages/react-app/src/ceramic/bootstrap.js +++ b/packages/react-app/src/ceramic/bootstrap.js @@ -5,7 +5,7 @@ const { createDefinition, publishSchema } = require("@ceramicstudio/idx-tools"); const { Ed25519Provider } = require("key-did-provider-ed25519"); const fromString = require("uint8arrays/from-string"); -const CERAMIC_URL = "https://ceramic-clay.3boxlabs.com"; +const CERAMIC_URL = "http://ceramic.signchain.xyz:7007"; const Profile = { doctype: "tile", @@ -38,6 +38,16 @@ const Profile = { type: "string", title: "userAddress", maxLength: 150, + }, + phoneNumber: { + type: 'string', + title: 'phoneNumber', + maxLength: 15 + }, + dob: { + type: 'string', + title: 'dob', + maxLength: 20 } }, }, diff --git a/packages/react-app/src/ceramic/config.json b/packages/react-app/src/ceramic/config.json index 4b36277..40230d2 100644 --- a/packages/react-app/src/ceramic/config.json +++ b/packages/react-app/src/ceramic/config.json @@ -1 +1 @@ -{"definitions":{"profile":"kjzl6cwe1jw148ha2ha9dz9btt8zdmdkdcu8v8kzd2kz7kwv0hfqfudiz8r8e2w"},"schemas":{"profile":"ceramic://k3y52l7qbv1frymlhyz3dom8wex9qgrfokf4l3rtp0y168cb7b8nl9241zvghqolc"}} \ No newline at end of file +{"definitions":{"profile":"kjzl6cwe1jw14bbssl2c6u8js1acvfhzwa56oxmq4pi60b6h1ztcrp4dzulreua"},"schemas":{"profile":"ceramic://k3y52l7qbv1frxmfl9wwnk1q87sw1qn316dj65o9ui6ic5rr73dbh6zuktv09h7nk"}} \ No newline at end of file diff --git a/packages/react-app/src/components/Documents/DocumentDetails.js b/packages/react-app/src/components/Documents/DocumentDetails.js index b65aaf9..41c9890 100644 --- a/packages/react-app/src/components/Documents/DocumentDetails.js +++ b/packages/react-app/src/components/Documents/DocumentDetails.js @@ -3,6 +3,7 @@ import {Button, Icon, Image, Label, Loader, Table} from "semantic-ui-react"; import SignWarning from "../warnings/SignWarning"; import {DetailsInfo, DocumentContainer, DocumentHeader} from "../styles/DocumentDetails.Style"; import {attachSignature, downloadFiles, getAllUsers, getSingleDocument, notarizeDoc,} from "../../lib/threadDb"; +import {sendSignedMail} from "../../lib/notifications" import {Link} from "react-router-dom"; import Sign from "../../images/icons/Sign.svg"; import Download from "../../images/icons/Download.svg"; @@ -16,6 +17,7 @@ const DocumentDetails = props => { const userInfo = JSON.parse(loggedUser); const documentId = decodeURIComponent(props.match.params.doc); const signatureId = decodeURIComponent(props.match.params.sig); + const urlParams = `${documentId}/${signatureId}`; const did = encodeURIComponent(userInfo.did); const [caller, setCaller] = useState({}); const [document, setDocument] = useState(null); @@ -38,6 +40,7 @@ const DocumentDetails = props => { documentId, signatureId, ); + console.log(documentInfo) setDocument(documentInfo); setLoading(false); } catch (e) { @@ -65,6 +68,7 @@ const DocumentDetails = props => { setSignedStatus(true); setSignWarning(false); setSignLoader(false); + await sendSignedMail(document.createdByEmail, { sender: caller.name, docId: urlParams }) } } catch (e) { // alert("Didn't sign it!"); diff --git a/packages/react-app/src/components/Profile/EditProfile.js b/packages/react-app/src/components/Profile/EditProfile.js index e761fad..edac137 100644 --- a/packages/react-app/src/components/Profile/EditProfile.js +++ b/packages/react-app/src/components/Profile/EditProfile.js @@ -7,13 +7,13 @@ import Warning from "./Warning"; import UpdateSuccess from "./updateSuccess"; import FinalUpdate from "./FinalUpdate"; -function EditProfile({ open, setOpen, user, idx }) { +function EditProfile({ open, setOpen, user, DOB, PhoneNumber, idx }) { const [name, setName] = useState(user.name); const [email, setEmail] = useState(user.email); - const [dob, setDob] = useState(user.profileDetails.DOB); + const [dob, setDob] = useState(DOB); const [userId, setUserId] = useState(user._id); - const [phoneNumber, setPhoneNumber] = useState(user.profileDetails.phoneNumber); + const [phoneNumber, setPhoneNumber] = useState(PhoneNumber); const [loader, setloader] = useState(false); const [warning, setWarning] = useState(false); const [success, setSuccess] = useState(false); diff --git a/packages/react-app/src/components/Profile/Profile.js b/packages/react-app/src/components/Profile/Profile.js index 75773fe..8ef888a 100644 --- a/packages/react-app/src/components/Profile/Profile.js +++ b/packages/react-app/src/components/Profile/Profile.js @@ -10,20 +10,28 @@ export default function Profile({ ceramic, idx }) { const [open, setOpen] = useState(false); const [user, setUser] = useState(null); const [userLoading, setUserLoading] = useState(true); + const [phoneNumber, setPhoneNumber] = useState(null); + const [dob, setDob] = useState(null); useEffect(() => { async function getUserData() { try { if (idx) { const data = await idx.get(definitions.profile, idx.id); - const userThreadDb = JSON.parse(localStorage.getItem("USER")); - setUser(userThreadDb); setUserLoading(false); if (data) { + setUser(data); + setPhoneNumber(data.phoneNumber) + setDob(data.dob) + setUserLoading(false); console.log("data fetched"); console.log("Data:", data); } else { + setUser(userThreadDb); + setPhoneNumber(userThreadDb.profileDetails.phoneNumber) + setDob(userThreadDb.profileDetails.DOB) + setUserLoading(false); // Registration on idx console.log("Something is wrong with IDX"); let notary = true; @@ -35,6 +43,8 @@ export default function Profile({ ceramic, idx }) { email: userThreadDb.email, notary: notary, userAddress: userThreadDb.address, + phoneNumber: userThreadDb.profileDetails.phoneNumber, + dob: userThreadDb.profileDetails.DOB }); } } @@ -48,7 +58,7 @@ export default function Profile({ ceramic, idx }) { return !userLoading ? ( user ? ( <> - +
@@ -57,10 +67,6 @@ export default function Profile({ ceramic, idx }) {

{idx.id}{" "}

-

- {user.address}{" "} -

-
@@ -88,7 +94,7 @@ export default function Profile({ ceramic, idx }) { Phone - {user.profileDetails.phoneNumber} + {phoneNumber} @@ -96,7 +102,7 @@ export default function Profile({ ceramic, idx }) { DOB - {user.profileDetails.DOB} + {dob} {/* diff --git a/packages/react-app/src/components/auth/SignUp.js b/packages/react-app/src/components/auth/SignUp.js index 381ddaf..0936bb4 100644 --- a/packages/react-app/src/components/auth/SignUp.js +++ b/packages/react-app/src/components/auth/SignUp.js @@ -49,6 +49,8 @@ function SignUp({ authStatus, setUserStatus, identity, address, idx, seed }) { notary: notary, joindate: moment(new Date()).format("ll"), userAddress: address, + phoneNumber: 'NA', + dob: 'NA' }); } catch (e) { console.log("Failed to create profile on IDX"); diff --git a/packages/react-app/src/lib/notifications.js b/packages/react-app/src/lib/notifications.js index 7d3caf3..b4457d5 100644 --- a/packages/react-app/src/lib/notifications.js +++ b/packages/react-app/src/lib/notifications.js @@ -10,4 +10,16 @@ export const sendMail = async (recipients, data) => { }); return response; } - \ No newline at end of file + +export const sendSignedMail = async (recipients, data) => { + const url = process.env.REACT_APP_API_SERVER_URL + '/email/sign' + const response = await fetch(url, { + method: 'POST', + mode: 'cors', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({recipients: recipients, data: data}) // body data type must match "Content-Type" header + }); + return response; +} \ No newline at end of file diff --git a/packages/react-app/src/lib/threadDb.js b/packages/react-app/src/lib/threadDb.js index ad56cca..84d1a64 100644 --- a/packages/react-app/src/lib/threadDb.js +++ b/packages/react-app/src/lib/threadDb.js @@ -230,7 +230,8 @@ export const registerDoc = async function(party, fileInfo, title, setSubmitting, createdBy: { name:caller.name, address: caller.address, - did: caller.did + did: caller.did, + email: caller.email }, signatureId: signatureID[0], documentHash: fileHash.toString("hex"), @@ -249,7 +250,8 @@ export const registerDoc = async function(party, fileInfo, title, setSubmitting, createdBy: { name:caller.name, address: caller.address, - _id: caller._id + _id: caller._id, + email: caller.email }, sharedWith: sharedParty, date: date.toDateString(), @@ -400,6 +402,7 @@ export const getSingleDocument = async function(address, tx, writeContracts, doc let value = { createdBy: document.createdBy.name, createdByDid: document.createdBy.did, + createdByEmail: document.createdBy.email, docId: document._id, hash: hash, documentLocation:document.fileLocation, @@ -512,7 +515,9 @@ export const updateUserProfile = async function(name, email, dob, phoneNumber,us name: name, email: email, notary: notary, - userAddress: user[0].address + userAddress: user[0].address, + phoneNumber: phoneNumber, + dob: dob }); console.log("Updated on IDX!!!")