Skip to content

Commit 06253fe

Browse files
authored
Merge pull request #122 from kleros/feat/custom-buyer
feat(web): custom buyer flow
2 parents 9fcb1de + 1368942 commit 06253fe

File tree

11 files changed

+433
-157
lines changed

11 files changed

+433
-157
lines changed
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import React from "react";
2+
import styled from "styled-components";
3+
import { hoverShortTransitionTiming } from "styles/commonStyles";
4+
import Arrow from "svgs/icons/arrow-down.svg";
5+
6+
const Label = styled.label`
7+
${hoverShortTransitionTiming}
8+
font-size: 12px;
9+
cursor: pointer;
10+
transition: color 0.2s ease;
11+
color: ${({ theme }) => theme.primaryBlue};
12+
`;
13+
14+
const StyledArrow = styled(Arrow) <{ isOpen: boolean }>`
15+
${hoverShortTransitionTiming}
16+
margin-left: 6px;
17+
width: 9px;
18+
height: 9px;
19+
transition: transform 0.25s ease, fill 0.25s ease;
20+
transform: rotate(${({ isOpen }) => (isOpen ? 180 : 0)}deg);
21+
fill: ${({ theme }) => theme.primaryBlue};
22+
`;
23+
24+
const StyledButton = styled.button`
25+
display: flex;
26+
align-items: center;
27+
justify-content: center;
28+
border: none;
29+
background: transparent;
30+
padding: 0;
31+
cursor: pointer;
32+
outline: none;
33+
34+
&:focus-visible {
35+
box-shadow: 0 0 0 2px ${({ theme }) => theme.primaryBlue};
36+
}
37+
38+
:hover {
39+
label {
40+
color: ${({ theme }) => theme.secondaryBlue};
41+
}
42+
svg {
43+
fill: ${({ theme }) => theme.secondaryBlue};
44+
}
45+
}
46+
`;
47+
48+
interface ISimpleToggleButton
49+
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
50+
isOpen: boolean;
51+
label: string;
52+
}
53+
54+
const SimpleToggleButton: React.FC<ISimpleToggleButton> = ({
55+
isOpen,
56+
label,
57+
onClick
58+
}) => (
59+
<StyledButton {...{ onClick }}>
60+
<Label>{label}</Label>
61+
<StyledArrow {...{ isOpen }} />
62+
</StyledButton>
63+
);
64+
65+
export default SimpleToggleButton;
Lines changed: 128 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import React, { createContext, useState, useContext, useEffect } from "react";
1+
import React, { createContext, useContext, useState, useCallback, useMemo } from "react";
2+
import { useLocalStorage } from "hooks/useLocalStorage";
23

34
export interface IToken {
45
symbol: string;
@@ -12,100 +13,74 @@ interface INewTransactionContext {
1213
escrowTitle: string;
1314
setEscrowTitle: (title: string) => void;
1415
deliverableText: string;
15-
setDeliverableText: (deliverableText: string) => void;
16+
setDeliverableText: (text: string) => void;
1617
deliverableFile: File | undefined;
17-
setDeliverableFile: (deliverableFile: File | undefined) => void;
18+
setDeliverableFile: (file: File | undefined) => void;
1819
extraDescriptionUri: string;
19-
setExtraDescriptionUri: (extraDescriptionUri: string) => void;
20+
setExtraDescriptionUri: (uri: string) => void;
2021
transactionUri: string;
21-
setTransactionUri: (transactionUri: string) => void;
22+
setTransactionUri: (uri: string) => void;
2223
isFileUploading: boolean;
23-
setIsFileUploading: (isFileUploading: boolean) => void;
24+
setIsFileUploading: (v: boolean) => void;
2425
receivingQuantity: string;
25-
setReceivingQuantity: (quantity: string) => void;
26+
setReceivingQuantity: (qty: string) => void;
2627
receivingToken: string;
2728
setReceivingToken: (token: string) => void;
2829
sellerAddress: string;
29-
setSellerAddress: (address: string) => void;
30+
setSellerAddress: (addr: string) => void;
3031
sendingQuantity: string;
31-
setSendingQuantity: (quantity: string) => void;
32+
setSendingQuantity: (qty: string) => void;
3233
sendingToken: IToken;
3334
setSendingToken: (token: IToken) => void;
3435
buyerAddress: string;
35-
setBuyerAddress: (address: string) => void;
36+
setBuyerAddress: (addr: string) => void;
37+
isBuyerAddressCustom: boolean;
38+
setIsBuyerAddressCustom: (v: boolean) => void;
3639
deadline: string;
37-
setDeadline: (deadline: string) => void;
40+
setDeadline: (d: string) => void;
3841
notificationEmail: string;
3942
setNotificationEmail: (email: string) => void;
4043
resetContext: () => void;
4144
hasSufficientNativeBalance: boolean;
42-
setHasSufficientNativeBalance: (hasSufficientNativeBalance: boolean) => void;
45+
setHasSufficientNativeBalance: (v: boolean) => void;
4346
isRecipientAddressResolved: boolean;
44-
setIsRecipientAddressResolved: (isRecipientAddressResolved: boolean) => void;
47+
setIsRecipientAddressResolved: (v: boolean) => void;
48+
isBuyerAddressResolved: boolean;
49+
setIsBuyerAddressResolved: (v: boolean) => void;
4550
}
4651

47-
const NewTransactionContext = createContext<INewTransactionContext>({
48-
escrowType: "",
49-
setEscrowType: () => {},
50-
escrowTitle: "",
51-
setEscrowTitle: () => {},
52-
deliverableText: "",
53-
setDeliverableText: () => {},
54-
transactionUri: "",
55-
setTransactionUri: () => {},
56-
isFileUploading: false,
57-
setIsFileUploading: () => {},
58-
deliverableFile: undefined,
59-
setDeliverableFile: () => {},
60-
extraDescriptionUri: "",
61-
setExtraDescriptionUri: () => {},
62-
receivingQuantity: "",
63-
setReceivingQuantity: () => {},
64-
receivingToken: "",
65-
setReceivingToken: () => {},
66-
sellerAddress: "",
67-
setSellerAddress: () => {},
68-
sendingQuantity: "",
69-
setSendingQuantity: () => {},
70-
sendingToken: { address: "native", symbol: "", logo: "" },
71-
setSendingToken: () => {},
72-
buyerAddress: "",
73-
setBuyerAddress: () => {},
74-
deadline: "",
75-
setDeadline: () => {},
76-
notificationEmail: "",
77-
setNotificationEmail: () => {},
78-
resetContext: () => {},
79-
hasSufficientNativeBalance: true,
80-
setHasSufficientNativeBalance: () => {},
81-
isRecipientAddressResolved: false,
82-
setIsRecipientAddressResolved: () => {},
83-
});
52+
const initialToken: IToken = { address: "native", symbol: "", logo: "" };
8453

85-
export const useNewTransactionContext = () => useContext(NewTransactionContext);
54+
const NewTransactionContext = createContext<INewTransactionContext | undefined>(undefined);
55+
56+
export const useNewTransactionContext = () => {
57+
const context = useContext(NewTransactionContext);
58+
if (!context) throw new Error("Context Provider not found.");
59+
return context;
60+
};
8661

8762
export const NewTransactionProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
88-
const [escrowType, setEscrowType] = useState<string>(localStorage.getItem("escrowType") || "general");
89-
const [escrowTitle, setEscrowTitle] = useState<string>(localStorage.getItem("escrowTitle") || "");
90-
const [deliverableText, setDeliverableText] = useState<string>(localStorage.getItem("deliverableText") || "");
63+
const [escrowType, setEscrowType] = useLocalStorage("escrowType", "general");
64+
const [escrowTitle, setEscrowTitle] = useLocalStorage("escrowTitle", "");
65+
const [deliverableText, setDeliverableText] = useLocalStorage("deliverableText", "");
9166
const [deliverableFile, setDeliverableFile] = useState<File | undefined>();
92-
const [transactionUri, setTransactionUri] = useState<string>(localStorage.getItem("transactionUri") || "");
93-
const [extraDescriptionUri, setExtraDescriptionUri] = useState<string>(
94-
localStorage.getItem("extraDescriptionUri") || ""
95-
);
96-
const [isFileUploading, setIsFileUploading] = useState<boolean>(false);
97-
const [hasSufficientNativeBalance, setHasSufficientNativeBalance] = useState<boolean>(true);
98-
const [receivingQuantity, setReceivingQuantity] = useState<string>(localStorage.getItem("receivingQuantity") || "");
99-
const [receivingToken, setReceivingToken] = useState<string>(localStorage.getItem("receivingToken") || "");
100-
const [sellerAddress, setSellerAddress] = useState<string>(localStorage.getItem("sellerAddress") || "");
101-
const [sendingQuantity, setSendingQuantity] = useState<string>(localStorage.getItem("sendingQuantity") || "");
102-
const [sendingToken, setSendingToken] = useState<IToken>(JSON.parse(localStorage.getItem("sendingToken") ?? "null") || { address: "native", symbol: "", logo: "" });
103-
const [buyerAddress, setBuyerAddress] = useState<string>(localStorage.getItem("buyerAddress") ?? "");
67+
const [transactionUri, setTransactionUri] = useLocalStorage("transactionUri", "");
68+
const [extraDescriptionUri, setExtraDescriptionUri] = useLocalStorage("extraDescriptionUri", "");
69+
const [isFileUploading, setIsFileUploading] = useState(false);
70+
const [hasSufficientNativeBalance, setHasSufficientNativeBalance] = useState(true);
71+
const [receivingQuantity, setReceivingQuantity] = useLocalStorage("receivingQuantity", "");
72+
const [receivingToken, setReceivingToken] = useLocalStorage("receivingToken", "");
73+
const [sellerAddress, setSellerAddress] = useLocalStorage("sellerAddress", "");
74+
const [sendingQuantity, setSendingQuantity] = useLocalStorage("sendingQuantity", "");
75+
const [sendingToken, setSendingToken] = useLocalStorage("sendingToken", initialToken);
76+
const [buyerAddress, setBuyerAddress] = useLocalStorage("buyerAddress", "");
77+
const [isBuyerAddressCustom, setIsBuyerAddressCustom] = useLocalStorage("isBuyerAddressCustom", false);
10478
const [isRecipientAddressResolved, setIsRecipientAddressResolved] = useState(false);
105-
const [deadline, setDeadline] = useState<string>(localStorage.getItem("deadline") || "");
106-
const [notificationEmail, setNotificationEmail] = useState<string>(localStorage.getItem("notificationEmail") || "");
79+
const [isBuyerAddressResolved, setIsBuyerAddressResolved] = useState(false);
80+
const [deadline, setDeadline] = useLocalStorage("deadline", "");
81+
const [notificationEmail, setNotificationEmail] = useLocalStorage("notificationEmail", "");
10782

108-
const resetContext = () => {
83+
const resetContext = useCallback(() => {
10984
setEscrowType("general");
11085
setEscrowTitle("");
11186
setDeliverableText("");
@@ -117,84 +92,96 @@ export const NewTransactionProvider: React.FC<{ children: React.ReactNode }> = (
11792
setReceivingToken("");
11893
setSellerAddress("");
11994
setSendingQuantity("");
120-
setSendingToken({ address: "native", symbol: "", logo: "" });
95+
setSendingToken(initialToken);
12196
setBuyerAddress("");
97+
setIsBuyerAddressCustom(false);
12298
setDeadline("");
12399
setNotificationEmail("");
124100
setHasSufficientNativeBalance(true);
125-
};
126-
127-
useEffect(() => {
128-
localStorage.setItem("escrowType", escrowType);
129-
localStorage.setItem("escrowTitle", escrowTitle);
130-
localStorage.setItem("deliverableText", deliverableText);
131-
localStorage.setItem("extraDescriptionUri", extraDescriptionUri);
132-
localStorage.setItem("transactionUri", transactionUri);
133-
localStorage.setItem("receivingQuantity", receivingQuantity);
134-
localStorage.setItem("receivingToken", receivingToken);
135-
localStorage.setItem("buyerAddress", buyerAddress);
136-
localStorage.setItem("sendingQuantity", sendingQuantity);
137-
localStorage.setItem("sendingToken", JSON.stringify(sendingToken));
138-
localStorage.setItem("sellerAddress", sellerAddress);
139-
localStorage.setItem("deadline", deadline);
140-
localStorage.setItem("notificationEmail", notificationEmail);
101+
setIsRecipientAddressResolved(false);
102+
setIsBuyerAddressResolved(false);
141103
}, [
142-
escrowType,
143-
escrowTitle,
144-
deliverableText,
145-
extraDescriptionUri,
146-
transactionUri,
147-
receivingQuantity,
148-
receivingToken,
149-
buyerAddress,
150-
sendingQuantity,
151-
sendingToken,
152-
sellerAddress,
153-
deadline,
154-
notificationEmail,
104+
setEscrowType,
105+
setEscrowTitle,
106+
setDeliverableText,
107+
setExtraDescriptionUri,
108+
setTransactionUri,
109+
setReceivingQuantity,
110+
setReceivingToken,
111+
setSellerAddress,
112+
setSendingQuantity,
113+
setSendingToken,
114+
setBuyerAddress,
115+
setIsBuyerAddressCustom,
116+
setDeadline,
117+
setNotificationEmail,
155118
]);
156119

157-
return (
158-
<NewTransactionContext.Provider
159-
value={{
160-
escrowType,
161-
setEscrowType,
162-
escrowTitle,
163-
setEscrowTitle,
164-
deliverableText,
165-
setDeliverableText,
166-
deliverableFile,
167-
setDeliverableFile,
168-
extraDescriptionUri,
169-
setExtraDescriptionUri,
170-
transactionUri,
171-
setTransactionUri,
172-
isFileUploading,
173-
setIsFileUploading,
174-
receivingQuantity,
175-
setReceivingQuantity,
176-
receivingToken,
177-
setReceivingToken,
178-
buyerAddress,
179-
setBuyerAddress,
180-
sendingQuantity,
181-
setSendingQuantity,
182-
hasSufficientNativeBalance,
183-
setHasSufficientNativeBalance,
184-
sendingToken,
185-
setSendingToken,
186-
sellerAddress,
187-
setSellerAddress,
188-
isRecipientAddressResolved,
189-
setIsRecipientAddressResolved,
190-
deadline,
191-
setDeadline,
192-
notificationEmail,
193-
setNotificationEmail,
194-
resetContext,
195-
}}
196-
>
197-
{children}
198-
</NewTransactionContext.Provider>
120+
const contextValues = useMemo(
121+
() => ({
122+
escrowType,
123+
setEscrowType,
124+
escrowTitle,
125+
setEscrowTitle,
126+
deliverableText,
127+
setDeliverableText,
128+
deliverableFile,
129+
setDeliverableFile,
130+
extraDescriptionUri,
131+
setExtraDescriptionUri,
132+
transactionUri,
133+
setTransactionUri,
134+
isFileUploading,
135+
setIsFileUploading,
136+
receivingQuantity,
137+
setReceivingQuantity,
138+
receivingToken,
139+
setReceivingToken,
140+
buyerAddress,
141+
setBuyerAddress,
142+
isBuyerAddressCustom,
143+
setIsBuyerAddressCustom,
144+
sendingQuantity,
145+
setSendingQuantity,
146+
hasSufficientNativeBalance,
147+
setHasSufficientNativeBalance,
148+
sendingToken,
149+
setSendingToken,
150+
sellerAddress,
151+
setSellerAddress,
152+
isRecipientAddressResolved,
153+
setIsRecipientAddressResolved,
154+
isBuyerAddressResolved,
155+
setIsBuyerAddressResolved,
156+
deadline,
157+
setDeadline,
158+
notificationEmail,
159+
setNotificationEmail,
160+
resetContext,
161+
}),
162+
[
163+
escrowType,
164+
escrowTitle,
165+
deliverableText,
166+
deliverableFile,
167+
extraDescriptionUri,
168+
transactionUri,
169+
isFileUploading,
170+
receivingQuantity,
171+
receivingToken,
172+
buyerAddress,
173+
isBuyerAddressCustom,
174+
sendingQuantity,
175+
hasSufficientNativeBalance,
176+
sendingToken,
177+
sellerAddress,
178+
isRecipientAddressResolved,
179+
isBuyerAddressResolved,
180+
deadline,
181+
notificationEmail,
182+
resetContext,
183+
]
199184
);
185+
186+
return <NewTransactionContext.Provider value={contextValues}>{children}</NewTransactionContext.Provider>;
200187
};

0 commit comments

Comments
 (0)