Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User lookup consent #1737

Merged
merged 13 commits into from
Nov 15, 2021
3 changes: 1 addition & 2 deletions packages/common-theme/src/Hooks/useLongPress.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,7 @@ export const useLongPress = (
}
}
}

}, [onLongPress, delay]
}, [clear]
)

return {
Expand Down
2 changes: 1 addition & 1 deletion packages/files-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"@babel/core": "^7.12.10",
"@babel/runtime": "^7.0.0",
"@chainsafe/browser-storage-hooks": "^1.0.1",
"@chainsafe/files-api-client": "^1.18.19",
"@chainsafe/files-api-client": "^1.18.20",
"@chainsafe/web3-context": "1.1.4",
"@lingui/core": "^3.7.2",
"@lingui/react": "^3.7.2",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { LookupUserRequest } from "@chainsafe/files-api-client"
import { t } from "@lingui/macro"
import { useCallback, useState } from "react"
import { useFilesApi } from "../../../../Contexts/FilesApiContext"
Expand All @@ -25,8 +24,7 @@ export const useLookupSharedFolderUser = () => {
))

if (foundIntersectingUsers.length) {
setUsersError(t`User ${
centerEllipsis(foundIntersectingUsers[0].label)
setUsersError(t`User ${centerEllipsis(foundIntersectingUsers[0].label)
} is both a reader and writer`)
} else {
setUsersError("")
Expand All @@ -36,7 +34,11 @@ export const useLookupSharedFolderUser = () => {
const handleLookupUser = useCallback(async (inputVal: string, permission: SharedFolderUserPermission) => {
if (inputVal === "") return []

const lookupBody: LookupUserRequest = {}
const lookupBody = {
public_address: undefined as string | undefined,
identity_public_key: undefined as string | undefined,
username: undefined as string | undefined
}
const ethAddressRegex = new RegExp("^0(x|X)[a-fA-F0-9]{40}$") // Eth Address Starting with 0x and 40 HEX chars
const pubKeyRegex = new RegExp("^0(x|X)[a-fA-F0-9]{66}$") // Compressed public key, 66 chars long

Expand All @@ -49,7 +51,7 @@ export const useLookupSharedFolderUser = () => {
}

try {
const result = await filesApiClient.lookupUser(lookupBody)
const result = await filesApiClient.lookupUser(lookupBody.username, lookupBody.public_address, lookupBody.identity_public_key)
if (!result) return []

const usersList = permission === "read" ? sharedFolderReaders : sharedFolderWriters
Expand Down
177 changes: 88 additions & 89 deletions packages/files-ui/src/Components/Modules/Settings/Profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import {
useToasts,
RadioInput,
TextInput,
CheckIcon
CheckIcon,
CheckboxInput
} from "@chainsafe/common-components"
import {
makeStyles,
Expand Down Expand Up @@ -93,8 +94,7 @@ const useStyles = makeStyles(({ constants, breakpoints, palette, typography }: C
},
button: {
width: 200,
margin: `0px ${constants.generalUnit * 0.5}px ${
constants.generalUnit * 4
margin: `0px ${constants.generalUnit * 0.5}px ${constants.generalUnit * 4
}px`
},
icon: {
Expand Down Expand Up @@ -165,7 +165,7 @@ const useStyles = makeStyles(({ constants, breakpoints, palette, typography }: C
},
usernameForm: {
display: "flex",
marginBottom: constants.generalUnit * 4,
marginBottom: constants.generalUnit,
"& svg": {
fill: palette.success.main
}
Expand All @@ -188,14 +188,14 @@ const profileValidation = yup.object().shape({
const ProfileView = () => {
const { themeKey, setTheme } = useThemeSwitcher()
const { addToast } = useToasts()
const { profile, updateProfile, addUsername, lookupOnUsername } = useUser()
const { profile, updateProfile, addUsername, lookupOnUsername, toggleLookupConsent } = useUser()
const { publicKey } = useThresholdKey()
const [updatingProfile, setUpdatingProfile] = useState(false)
const [showUsernameForm, setShowUsernameForm] = useState(false)
const [username, setUsername] = useState("")
const [usernameData, setUsernameData] = useState({ error: "", loading: false })
const formik = useFormik({
initialValues:{
initialValues: {
firstName: profile?.firstName || "",
lastName: profile?.lastName || ""
// email: profile?.email || ""
Expand Down Expand Up @@ -400,90 +400,89 @@ const ProfileView = () => {
</div>
</div>
}
{profile?.username
? <div className={classes.inputBoxContainer}>
<Typography
component="p"
className={classes.label}
>
<Trans>Username</Trans>
</Typography>
<Typography
component="p"
className={classes.subLabel}
>
<Trans>This username is public</Trans>
</Typography>
<div className={classes.usernameForm}>
<TextInput
disabled={true}
value={profile.username}
className={classes.usernameInput}
/>
</div>
</div>
: <div className={classes.inputBoxContainer}>
<Typography
component="p"
className={classes.label}
>
<Trans>Username</Trans>
</Typography>
{showUsernameForm
? <div>
<Typography
component="p"
className={classes.subLabel}
>
<Trans>Usernames are public and can&apos;t be changed after creation.</Trans>
</Typography>
<form
onSubmit={onSubmitUsername}
className={classes.usernameForm}
>
<TextInput
placeholder={t`Username`}
name="username"
size="medium"
value={username}
className={classes.usernameInput}
RightIcon={username && !usernameData.error ? CheckIcon : undefined}
onChange={onUsernameChange}
captionMessage={usernameData.error}
state={usernameData.error ? "error" : "normal"}
data-cy="profile-username-input"
/>
<div>
<Button
type="submit"
disabled={usernameData.loading || !!usernameData.error || !username}
loading={usernameData.loading}
>
{usernameData.loading ? t`Setting Username` : t`Set Username`}
</Button>
</div>
</form>
<div className={classes.inputBoxContainer}>
{profile?.username
? <>
<Typography
component="p"
className={classes.label}
>
<Trans>Username</Trans>
</Typography>
<div className={classes.usernameForm}>
<TextInput
disabled={true}
value={profile.username}
className={classes.usernameInput}
/>
</div>
: <div>
<Typography
component="p"
className={classes.subLabel}
>
<span>
<Trans>You haven&apos;t set a username yet.</Trans>
</span>
{" "}
<span
className={classes.buttonLink}
onClick={() => setShowUsernameForm(true)}
</>
: <>
<Typography
component="p"
className={classes.label}
>
<Trans>Username</Trans>
</Typography>
{showUsernameForm
? <div>
<Typography
component="p"
className={classes.subLabel}
>
<Trans>Add a username</Trans>
</span>
</Typography>
</div>
}
</div>
}
<Trans>Usernames are public and can&apos;t be changed after creation.</Trans>
</Typography>
<form
onSubmit={onSubmitUsername}
className={classes.usernameForm}
>
<TextInput
placeholder={t`Username`}
name="username"
size="medium"
value={username}
className={classes.usernameInput}
RightIcon={username && !usernameData.error ? CheckIcon : undefined}
onChange={onUsernameChange}
captionMessage={usernameData.error}
state={usernameData.error ? "error" : "normal"}
data-cy="profile-username-input"
/>
<div>
<Button
type="submit"
disabled={usernameData.loading || !!usernameData.error || !username}
loading={usernameData.loading}
>
{usernameData.loading ? t`Setting Username` : t`Set Username`}
</Button>
</div>
</form>
</div>
: <div>
<Typography
component="p"
className={classes.subLabel}
>
<span>
<Trans>You haven&apos;t set a username yet.</Trans>
</span>
{" "}
<span
className={classes.buttonLink}
onClick={() => setShowUsernameForm(true)}
>
<Trans>Add a username</Trans>
</span>
</Typography>
</div>
}
</>
}
<CheckboxInput label={t`Allow lookup by sharing key, wallet address or username`}
value={profile?.lookupConsent || false}
onChange={toggleLookupConsent} />
</div>
<FormikProvider value={formik}>
<Form>
<div className={classes.inputBoxContainer}>
Expand Down Expand Up @@ -640,7 +639,7 @@ const ProfileView = () => {
>
<Trans>Language</Trans>
</Typography>
<LanguageSelection/>
<LanguageSelection />
</div>
</Grid>
</Grid>
Expand Down
40 changes: 35 additions & 5 deletions packages/files-ui/src/Contexts/UserContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export type Profile = {
email?: string
createdAt?: Date
username?: string
lookupConsent: boolean
}

interface ILocalStore {
Expand All @@ -39,6 +40,7 @@ interface IUserContext {
addUsername: (username: string) => Promise<void>
removeUser(): void
getProfileTitle(): string
toggleLookupConsent(): Promise<void>
}

const UserContext = React.createContext<IUserContext | undefined>(undefined)
Expand Down Expand Up @@ -72,7 +74,8 @@ const UserProvider = ({ children }: UserContextProps) => {
email: profileApiData.email,
publicAddress: profileApiData.public_address?.toLowerCase(),
createdAt: profileApiData.created_at,
username: profileApiData.username
username: profileApiData.username,
lookupConsent: profileApiData.user_lookup_consent || false
}
setProfile(profileState)
return Promise.resolve()
Expand Down Expand Up @@ -156,7 +159,7 @@ const UserProvider = ({ children }: UserContextProps) => {
if (!profile) return Promise.reject("Profile not initialized")

try {
await filesApiClient.updateUser({
const result = await filesApiClient.updateUser({
first_name: profile.firstName || "",
last_name: profile.lastName || "",
email: profile.email || "",
Expand All @@ -165,7 +168,33 @@ const UserProvider = ({ children }: UserContextProps) => {

setProfile({
...profile,
username
username: result.username
})
return Promise.resolve()
} catch (error: any) {
console.error(error)
return Promise.reject(
Array.isArray(error.error.details)
? error.error.details.map((e: Details) => e.message).join(",")
: t`There was an error when setting username.`
)
}
}

const toggleLookupConsent = async () => {
if (!profile) return Promise.reject("Profile not initialized")
try {
const result = await filesApiClient.updateUser({
first_name: profile.firstName || "",
last_name: profile.lastName || "",
email: profile.email || "",
username: profile.username,
lookup_consent_flag: !profile.lookupConsent
})

setProfile({
...profile,
lookupConsent: result.user_lookup_consent || false
})
return Promise.resolve()
} catch (error: any) {
Expand All @@ -181,7 +210,7 @@ const UserProvider = ({ children }: UserContextProps) => {
const lookupOnUsername = async (username: string) => {
if (!profile) return false
try {
const alreadyExists = await filesApiClient.lookupUser({ username })
const alreadyExists = await filesApiClient.lookupUser(username)
return !!alreadyExists
} catch (error) {
console.error(error)
Expand Down Expand Up @@ -217,7 +246,8 @@ const UserProvider = ({ children }: UserContextProps) => {
removeUser,
addUsername,
lookupOnUsername,
getProfileTitle
getProfileTitle,
toggleLookupConsent
}}
>
{children}
Expand Down
6 changes: 3 additions & 3 deletions packages/files-ui/src/locales/de/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ msgstr ""
msgid "Adding you to the shared folder..."
msgstr ""

msgid "Allow lookup by sharing key, wallet address or username"
msgstr ""

msgid "An error occurred:"
msgstr "Es ist ein Fehler aufgetreten:"

Expand Down Expand Up @@ -763,9 +766,6 @@ msgstr ""
msgid "This username is already taken"
msgstr ""

msgid "This username is public"
msgstr "Dieser Benutzername ist öffentlich"

msgid "This website uses cookies"
msgstr ""

Expand Down
Loading