Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 43 additions & 2 deletions components/CreateAgreement/NavPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ import {
fW,
} from "./styles";
import { useMutation } from "urql";
import { saveAgreementMutation } from "../../modules/graphql/mutations";
import {
saveAgreementMutation,
sendEmailVerificationLinkMutation,
} from "../../modules/graphql/mutations";
import {
LOCATION_CLOUD,
LOCATION_PUBLIC_IPFS,
Expand All @@ -44,6 +47,7 @@ import { uploadFile, uploadToIpfs } from "../../modules/rest";
import { notifError } from "../../utils/notification";
import ModalConfirmAgreementDeletion from "../ModalConfirmAgreementDeletion/ModalConfirmAgreementDeletion";
import { getToken } from "../../utils/token";
import { isEmail } from "./utils";

const FILE_UPLOAD_ERROR_DEFAULT_MESSAGE = "Failed to upload file";

Expand All @@ -64,9 +68,9 @@ export default function NavPanel({ setLoading, page }: { setLoading: any; page:

const [isLoadingNextStep, setIsLoadingNextStep] = useState<boolean>(false);
const [isAuthorNotAddedPopupVisible, setIsAuthorNotAddedPopupVisible] = useState<boolean>(false);

const [isConfirmAgreementDeletionPopupVisible, setIsConfirmAgreementDeletionPopupVisible] =
useState<boolean>(false);
const [, sendEmailVerificationLinkRequest] = useMutation(sendEmailVerificationLinkMutation);

const validateFields = (values: CreationState, isSavingDraft: boolean = false): boolean => {
const errors: CreateAgreementFieldErrors = {};
Expand Down Expand Up @@ -203,8 +207,41 @@ export default function NavPanel({ setLoading, page }: { setLoading: any; page:
});
};

const sendEmailVerificationEmails = async (signers: string[], observers: string[]) => {
console.log("sendEmailVerificationEmails");
console.log({ signers, observers });

signers.forEach(async signer => {
if (isEmail(signer)) {
console.log(`seding an email to ${signer}`);
await sendEmailVerificationLinkRequest({
email: signer,
isSigner: true,
agreementTitle: values.title,
});
}
});

observers.forEach(async observer => {
if (isEmail(observer)) {
console.log(`seding an email to ${observer}`);
await sendEmailVerificationLinkRequest({
email: observer,
isSigner: false,
agreementTitle: values.title,
});
}
});
};

const handleSaveDraft = async () => {
console.log("handleSaveDraft");
const areFieldsValid = validateFields(values, true);
await sendEmailVerificationEmails(
values.signers.map(x => x.value),
values.observers.map(x => x.value)
);
console.log({ values });
if (areFieldsValid) {
const uploadFileData: any = await preuploadFile();
await handleCreateAgreement(uploadFileData?.filePath, uploadFileData?.agreementHash);
Expand Down Expand Up @@ -348,6 +385,10 @@ export default function NavPanel({ setLoading, page }: { setLoading: any; page:
const areFieldsValid = validateFields({ ...values, ...uploadedFileData });
if (areFieldsValid) {
if (isFinishButton) {
await sendEmailVerificationEmails(
values.signers.map(x => x.value),
values.observers.map(x => x.value)
);
await handleCreateAgreement();
} else {
handleNextStep();
Expand Down
7 changes: 7 additions & 0 deletions components/CreateAgreement/Steps/StepThree/validationUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,10 @@ export const validateAddress = (value: string): string | undefined => {
return "Invalid wallet address";
}
};

export const validateEmail = (value: string): string | undefined => {
const isValidEmail = value.match(/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/);
if (!isValidEmail) {
return "Invalid email address";
}
};
24 changes: 18 additions & 6 deletions components/CreateAgreement/Steps/StepTwo/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useRef, useMemo, useState } from "react";
import { Container, Flex, Input, Text, Button, Box, Switch, Label } from "theme-ui";
import { Container, Flex, Input, Text, Button, Box } from "theme-ui";
import {
inputCreateAgreementWithRightButton,
inputCreateAgreementError,
Expand All @@ -8,7 +8,7 @@ import {
addMeBtn,
plus,
} from "../../styles";
import { validateAddress, validateEnsDomains } from "../StepThree/validationUtils";
import { validateAddress, validateEmail, validateEnsDomains } from "../StepThree/validationUtils";
import { useCreateAgreement } from "../../../../hooks/useCreateAgreement";
import { useEditAgreement } from "../../../../hooks/useEditAgreement";
import FieldErrorMessage from "../../../Form/FieldErrorMessage";
Expand All @@ -23,6 +23,7 @@ import Icon from "../../../icon";
import { PlusIcon } from "./svg";
import styles from "./styles";
import { notifComingSoon } from "../../../../utils/notification";
import { isEmail } from "../../utils";

interface VerificationInfo {
title: string;
Expand Down Expand Up @@ -130,6 +131,7 @@ export default function StepTwo({ page }: { page: string }) {
if (userAlreadyObserver) {
return userRole === "signer" ? "Already exists as Observer" : "Observer is already added";
}

const isEns = value?.includes(".eth");
if (isEns) {
const error = validateEnsDomains(value);
Expand All @@ -140,13 +142,17 @@ export default function StepTwo({ page }: { page: string }) {
}

const isAddress = value?.startsWith("0x");

if (isAddress) {
const error = validateAddress(value);
if (error) return error;
}

if (!isEns && !isAddress) {
if (isEmail(value)) {
const error = validateEmail(value);
if (error) return error;
}

if (!isEns && !isAddress && !isEmail(value)) {
return "Invalid value";
}

Expand All @@ -166,6 +172,7 @@ export default function StepTwo({ page }: { page: string }) {
changeValue("errors", { ...values.errors, signers: validationError });
return;
}

changeValue("signers", [
...values.signers,
{ value: value.toLocaleLowerCase(), id: uniqueId() },
Expand Down Expand Up @@ -207,12 +214,13 @@ export default function StepTwo({ page }: { page: string }) {
return (
<Container sx={styles}>
<>
{/* Signers */}
<Box>
<Flex
sx={{ position: "relative", justifyContent: "space-between", alignItems: "center" }}
>
<Flex sx={{ alignItems: "center" }}>
<Text sx={labelSigners}>Signers (ENS name or address) *</Text>
<Text sx={labelSigners}>Signers (ENS name, Ethereum address, or email) *</Text>
<Tooltip
title="Add users that will sign this agreement."
transform="translate(-57%, 0)"
Expand Down Expand Up @@ -259,6 +267,8 @@ export default function StepTwo({ page }: { page: string }) {
<FieldErrorMessage error={values?.errors?.signers} isAbsolutePosition={false} />
<TagList items={values.signers} type="signers" onDelete={onDelete} />
</Box>

{/* Observers */}
<Box>
<Flex
sx={{
Expand All @@ -278,7 +288,7 @@ export default function StepTwo({ page }: { page: string }) {
minHeight: "25px",
}}
>
Observers (ENS name or adderess){" "}
Observers (ENS name, Ethereum adderess, or email){" "}
</Text>
<Tooltip
title="Add users that will be able to see but not sign an agreement."
Expand Down Expand Up @@ -333,6 +343,8 @@ export default function StepTwo({ page }: { page: string }) {
<FieldErrorMessage error={values?.errors?.observers} isAbsolutePosition={false} />
<TagList items={values.observers} type="observers" onDelete={onDelete} />
</Box>

{/* Required Verifications */}
<Box sx={{ mt: "10px" }}>
<Flex
sx={{
Expand Down
1 change: 1 addition & 0 deletions components/CreateAgreement/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const variants: Variants = {
visible: { opacity: 1 },
enter: { opacity: 0.5 },
};

export const withFade = (component: React.ReactElement, key: number | string) => {
return (
<motion.main
Expand Down
1 change: 1 addition & 0 deletions components/CreateAgreement/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const isEmail = (x: string) => x?.includes("@");
2 changes: 1 addition & 1 deletion components/ModalEditObservers/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export default function ModalEditObservers({ agreement, isOpen, onExit, onSucces
<Text
sx={{ variant: "forms.label", ml: "3px", maxWidth: "unset", minHeight: "25px" }}
>
Observers (ENS name or adderess)
Observers (ENS name, Ethereum adderess, or email)
</Text>
<Tooltip
title="Add users that will be able to see but not sign an agreement."
Expand Down
4 changes: 2 additions & 2 deletions components/ViewAgreement/AgreementObserversList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ export const AgreementObserversList = ({ observers }: Props) => {
<table className="participantsTable">
<thead>
<tr>
<th>Observer Name</th>
<th>Observer Address</th>
<th>Name</th>
<th>Address/Email/ENS</th>
</tr>
</thead>
<tbody>
Expand Down
4 changes: 2 additions & 2 deletions components/ViewAgreement/AgreementSignersList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ export const AgreementSignersList = ({ signers }: Props) => {
<table className="participantsTable">
<thead>
<tr>
<th>Signer Name</th>
<th>Signer Address</th>
<th>Name</th>
<th>Address/Email/ENS</th>
<th>Signature status</th>
<th>Proof of signature</th>
</tr>
Expand Down
6 changes: 3 additions & 3 deletions components/ViewAgreement/ObserverRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ export const ObserverRow = ({ observer }: Props) => {

const address = useMemo<string>(
() =>
observer?.wallet?.address
? observer.wallet.address
: !!observer?.email?.startsWith("0x")
!!observer?.email?.length
? observer?.email
: observer?.wallet?.address
? observer?.wallet?.address
: "",
[observer]
);
Expand Down
6 changes: 3 additions & 3 deletions components/ViewAgreement/SignerRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ export const SignerRow = ({ signer, signProof, viewProof }: Props) => {

const address = useMemo<string>(
() =>
signer?.wallet?.address
? signer.wallet.address
: !!signer?.email?.startsWith("0x")
!!signer?.email?.length
? signer?.email
: signer?.wallet?.address
? signer?.wallet?.address
: "",
[signer]
);
Expand Down
2 changes: 1 addition & 1 deletion components/ViewAgreement/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { Box, Button, Flex } from "theme-ui";
import { useRouter } from "next/router";
import { useMutation, useQuery, useClient } from "urql";
import { useClient } from "urql";

import { agreementById } from "../../modules/graphql/queries";
import {
Expand Down
43 changes: 33 additions & 10 deletions modules/authProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,23 @@ const AuthProvider = (props?: Partial<ProviderProps<AuthProps>>) => {
profile: null,
//isTrezor: false,
});
const { push, pathname } = useRouter();
const { push, pathname, query, isReady } = useRouter();
const [, loginRequest] = useMutation(loginMutation);
const [, verifyMyEmailRequest] = useMutation(verifyMyEmailMutation);

const auth = useLock();

const loginStarted = useRef(false);

const web3ProviderRef = useRef<Web3Provider>();

async function login(connector?: ConnectorType, email?: string, emailVerificationSalt?: string) {
console.log("login()");
console.log({ query });
email = email ?? (query.email as string);
emailVerificationSalt = emailVerificationSalt ?? (query.emailVerificationSalt as string);
console.log({
email,
emailVerificationSalt,
});
// Prevent double loginRequest due to react dev useEffect[] runs twice
if (loginStarted.current) return;
loginStarted.current = true;
Expand Down Expand Up @@ -125,14 +131,18 @@ const AuthProvider = (props?: Partial<ProviderProps<AuthProps>>) => {
if (!account) return;
if (getToken()) return; // user already has a token

const res = await loginRequest({ address: account });
console.log("onAfterConnect");
console.log({ email, emailVerificationSalt });

const res = await loginRequest({ address: account, email });

const payload = res?.data?.login?.payload;
if (!payload) return;

const signature = await sign(payload);
const tokenRes = await loginRequest({
address: account,
email,
signature: signature,
});

Expand Down Expand Up @@ -227,7 +237,7 @@ const AuthProvider = (props?: Partial<ProviderProps<AuthProps>>) => {
//@ts-ignore
provider.value?.wc?.peerMeta?.name || null;
} catch (e) {
console.log("ERROR load web3", e);
console.error("ERROR load web3", e);
//setState((state) => ({ ...state, account: "" }));
loadedState.account = "";

Expand Down Expand Up @@ -296,9 +306,25 @@ const AuthProvider = (props?: Partial<ProviderProps<AuthProps>>) => {
return await web3ProviderRef.current?.resolveName(name);
}

async function loginWhenNecessary() {
const hasToken = Boolean(getToken());
const loadedConnector = await auth.getConnector();
if ((!loadedConnector || !hasToken) && pathname !== "/connect") {
// Redirect to the connect page
clearToken();
await push("/connect");
loginStarted.current = false;
} else {
// Perform user login
if (isReady && pathname !== "/connect") {
login();
}
}
}

useEffect(() => {
login();
}, []); // eslint-disable-line react-hooks/exhaustive-deps
loginWhenNecessary();
}, [isReady]); // eslint-disable-line react-hooks/exhaustive-deps

return (
<AuthContext.Provider
Expand All @@ -310,9 +336,6 @@ const AuthProvider = (props?: Partial<ProviderProps<AuthProps>>) => {
signTypedData,
_signTypedData,
resolveEns,
//loadProvider,
//handleChainChanged,
//web3: state,
...state,
}}
/>
Expand Down
1 change: 0 additions & 1 deletion modules/createAgreementProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { useRouter } from "next/router";
import { useState, createContext, ProviderProps, useEffect, useRef } from "react";
import { StringDecoder } from "string_decoder";
import {
AgreementLocation,
AgreementMethod,
Expand Down
Loading