Skip to content

Commit

Permalink
feat: add ui for selecting account in Welcome
Browse files Browse the repository at this point in the history
  • Loading branch information
Jack-Works committed Aug 8, 2019
1 parent 0298aa9 commit fa5ba06
Show file tree
Hide file tree
Showing 9 changed files with 167 additions and 55 deletions.
19 changes: 14 additions & 5 deletions src/_locales/en/messages.json
Expand Up @@ -90,13 +90,13 @@
"message": "Welcome to Maskbook"
},
"welcome_0_description": {
"message": "You can post on Facebook without allowing Facebook to stalk, analyze, or spy on you."
"message": "You can post on social networks without allowing them to stalk, analyze, or spy on you."
},
"welcome_0_new_user": {
"message": "New user?"
},
"welcome_0_connect_facebook": {
"message": "Connect Facebook"
"welcome_0_connect_maskbook": {
"message": "Setup Maskbook"
},
"welcome_0_old_user": {
"message": "Returning user?"
Expand All @@ -107,6 +107,15 @@
"welcome_0_caption": {
"message": "Lost your keypair backup? No worry. Simply start as a new user."
},
"welcome_1a1_title": {
"message": "Setup which account?"
},
"welcome_1a1_next": {
"message": "Next"
},
"welcome_1a1_didntfind": {
"message": "Didn't find your account?"
},
"welcome_1a2_title": {
"message": "Encrypt message in a Maskbook postbox"
},
Expand Down Expand Up @@ -162,7 +171,7 @@
"message": "Avoid any confusion before your first encrypted post."
},
"welcome_1a4_type_auto_subtitle2": {
"message": "This allows your friends to verify the connection between your Facebook account and your keypair."
"message": "This allows your friends to verify the connection between your social network account and your keypair."
},
"welcome_1a4_type_auto_switch": {
"message": "Prefer doing it manually?"
Expand All @@ -171,7 +180,7 @@
"message": "Add this to bio, or post on timeline, before your first encrypted post."
},
"welcome_1a4_type_manual_subtitle2": {
"message": "This allows your friends to verify the connection between your Facebook account and your keypair."
"message": "This allows your friends to verify the connection between your social network account and your keypair."
},
"welcome_1a4_type_manual_goto": {
"message": "Copy & Go to Profile"
Expand Down
19 changes: 14 additions & 5 deletions src/_locales/zh/messages.json
Expand Up @@ -91,13 +91,13 @@
"message": "歡迎使用 Maskbook"
},
"welcome_0_description": {
"message": "從此無需擔心 Facebook 追蹤、分析、窺視你的數字生活"
"message": "從此無需擔心社交網路追蹤、分析、窺視你的數字生活"
},
"welcome_0_new_user": {
"message": "新用戶?"
},
"welcome_0_connect_facebook": {
"message": "連接 Facebook 賬號"
"welcome_0_connect_maskbook": {
"message": "設置 Maskbook 賬號"
},
"welcome_0_old_user": {
"message": "老用戶?"
Expand All @@ -108,6 +108,15 @@
"welcome_0_caption": {
"message": "弄丟了備份檔案?不用擔心,當作自己是新用戶即可。"
},
"welcome_1a1_title": {
"message": "你希望為哪個賬戶設定 Maskbook?"
},
"welcome_1a1_next": {
"message": "確認"
},
"welcome_1a1_didntfind": {
"message": "沒有找到你的賬戶?"
},
"welcome_1a2_title": {
"message": "使用 Maskbook 的輸入框來加密"
},
Expand Down Expand Up @@ -163,7 +172,7 @@
"message": "避免好友感到迷惑"
},
"welcome_1a4_type_auto_subtitle2": {
"message": "這使得你的好友能夠驗證你的 Facebook 賬號與你的 Maskbook 公鑰都屬於你。"
"message": "這使得你的好友能夠驗證你的社交網路賬號與你的 Maskbook 公鑰都屬於你。"
},
"welcome_1a4_type_auto_switch": {
"message": "更願意手動操作?"
Expand All @@ -172,7 +181,7 @@
"message": "將這串文本添加到個人簡介或分享到時間線,在發佈第一條加密訊息之前。"
},
"welcome_1a4_type_manual_subtitle2": {
"message": "這使得你的好友能夠驗證你的 Facebook 賬號與你的 Maskbook 公鑰都屬於你。"
"message": "這使得你的好友能夠驗證你的社交網路賬號與你的 Maskbook 公鑰都屬於你。"
},
"welcome_1a4_type_manual_goto": {
"message": "拷貝並跳轉到個人簡介"
Expand Down
84 changes: 53 additions & 31 deletions src/components/InjectedComponents/SelectPeople.tsx
Expand Up @@ -20,27 +20,38 @@ interface PeopleInListProps {
person: Person
onClick(): void
disabled?: boolean
showAtNetwork?: boolean
}
const usePeopleInListStyle = makeStyles({
const usePeopleInListStyle = makeStyles(theme => ({
overflow: {
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
overflow: 'hidden',
},
})
networkHint: {
color: theme.palette.grey[500],
},
}))
/**
* Item in the list
*/
function PersonInList({ person, onClick, disabled }: PeopleInListProps) {
function PersonInList({ person, onClick, disabled, showAtNetwork }: PeopleInListProps) {
const classes = usePeopleInListStyle()
const name = person.nickname || person.identifier.userId
const withNetwork = (
<>
{name}
<span className={classes.networkHint}> @ {person.identifier.network}</span>
</>
)
return (
<ListItem button onClick={disabled ? void 0 : onClick}>
<ListItem button disabled={disabled} onClick={onClick}>
<ListItemAvatar>
<Avatar person={person} />
</ListItemAvatar>
<ListItemText
classes={{ primary: classes.overflow, secondary: classes.overflow }}
primary={person.nickname || person.identifier.userId}
primary={showAtNetwork ? withNetwork : name}
secondary={person.fingerprint ? person.fingerprint.toLowerCase() : undefined}
/>
</ListItem>
Expand All @@ -63,13 +74,18 @@ function PersonInChip({ disabled, onDelete, person }: PersonInChipProps) {
/>
)
}
interface SelectPeopleUI {
interface SelectPeopleUIProps {
ignoreMyself?: boolean
people: Person[]
selected: Person[]
frozenSelected: Person[]
onSetSelected: (selected: Person[]) => void
disabled?: boolean
hideSelectAll?: boolean
hideSelectNone?: boolean
showAtNetwork?: boolean
maxSelection?: number
classes?: Partial<Record<'root', string>>
}
const useStyles = makeStyles({
paper: { maxWidth: 500 },
Expand All @@ -82,8 +98,9 @@ const useStyles = makeStyles({
input: { flex: 1 },
button: { marginLeft: 8, padding: '2px 6px' },
})
export function SelectPeopleUI(props: SelectPeopleUI) {
export function SelectPeopleUI(props: SelectPeopleUIProps) {
const { people, frozenSelected, onSetSelected, selected, disabled, ignoreMyself } = props
const { hideSelectAll, hideSelectNone, showAtNetwork, maxSelection, classes: classesProp = {} } = props
const classes = useStyles()

const myself = useContext(CurrentUsingIdentityContext)
Expand Down Expand Up @@ -113,8 +130,12 @@ export function SelectPeopleUI(props: SelectPeopleUI) {
{geti18nString('select_none')}
</Button>
)

const showSelectAll = !hideSelectAll && listAfterSearch.length > 0 && typeof maxSelection === 'undefined'
const showSelectNone = !hideSelectNone && selected.length > 0

return (
<>
<div className={classesProp.root}>
<Box display="flex" className={classes.selectedArea}>
{frozenSelected.map(FrozenChip)}
{selected.map(RemovableChip)}
Expand All @@ -131,38 +152,39 @@ export function SelectPeopleUI(props: SelectPeopleUI) {
disabled={disabled}
/>
</Box>
{disabled ? (
undefined
) : (
<>
<Box display="flex">
{listAfterSearch.length > 0 && SelectAllButton}
{selected.length > 0 && SelectNoneButton}
</Box>
<Box flex={1}>
<List dense>
{listBeforeSearch.length > 0 && listBeforeSearch.length === 0 && (
<ListItem>
<ListItemText primary={geti18nString('not_found')} />
</ListItem>
)}
{listAfterSearch.map(PeopleListItem)}
</List>
</Box>
</>
)}
</>
<Box display="flex">
{showSelectAll && SelectAllButton}
{showSelectNone && SelectNoneButton}
</Box>
<Box flex={1}>
<List dense>
{listBeforeSearch.length > 0 && listBeforeSearch.length === 0 && (
<ListItem>
<ListItemText primary={geti18nString('not_found')} />
</ListItem>
)}
{listAfterSearch.map(PeopleListItem)}
</List>
</Box>
</div>
)

function PeopleListItem(person: Person) {
if (ignoreMyself && myself && person.identifier.equals(myself.identifier)) return null
return (
<PersonInList
showAtNetwork={showAtNetwork}
key={person.identifier.userId}
person={person}
disabled={disabled}
disabled={
disabled ||
(typeof maxSelection === 'number' &&
maxSelection >= 2 &&
frozenSelected.length + selected.length >= maxSelection)
}
onClick={() => {
onSetSelected(selected.concat(person))
if (maxSelection === 1) onSetSelected([person])
else onSetSelected(selected.concat(person))
setSearch('')
}}
/>
Expand Down
2 changes: 1 addition & 1 deletion src/components/InjectedComponents/SelectPeopleDialog.tsx
Expand Up @@ -25,7 +25,7 @@ const useStyles = makeStyles({
content: { padding: '0 12px' },
progress: { marginRight: 6 },
})
const ResponsiveDialog = withMobileDialog()(Dialog)
const ResponsiveDialog = withMobileDialog({ breakpoint: 'xs' })(Dialog)
export function SelectPeopleDialog(props: Props) {
const classes = useStyles()
const [people, select] = useState<Person[]>([] as Person[])
Expand Down
4 changes: 2 additions & 2 deletions src/components/Welcomes/0.tsx
Expand Up @@ -86,7 +86,7 @@ export default function Welcome({ create, restore, close }: Props) {
<LinedBox theme={theme}>
<Box flex={1}>
<Typography variant="body1">{geti18nString('welcome_0_new_user')}</Typography>
<Typography variant="h6">{geti18nString('welcome_0_connect_facebook')}</Typography>
<Typography variant="h6">{geti18nString('welcome_0_connect_maskbook')}</Typography>
</Box>
<VerticalCenter>
<Button
Expand All @@ -99,7 +99,7 @@ export default function Welcome({ create, restore, close }: Props) {
}}
variant="contained"
color="primary">
{geti18nString('welcome_0_connect_facebook')}
{geti18nString('welcome_0_connect_maskbook')}
</Button>
</VerticalCenter>
</LinedBox>
Expand Down
61 changes: 61 additions & 0 deletions src/components/Welcomes/1a1.tsx
@@ -0,0 +1,61 @@
import * as React from 'react'
import { getUrl } from '../../utils/utils'
import { geti18nString } from '../../utils/i18n'
import { Typography, Button, makeStyles } from '@material-ui/core'
import WelcomeContainer from './WelcomeContainer'
import { SelectPeopleUI } from '../InjectedComponents/SelectPeople'
import { useState } from 'react'
import { Person } from '../../database'

interface Props {
next(person: Person): void
didntFindAccount(): void
identities: Person[]
}
const useStyles = makeStyles(theme => ({
paper: {
padding: '2rem 1rem 1rem 1rem',
textAlign: 'center',
'& > *': {
marginBottom: theme.spacing(3),
},
},
button: {
minWidth: 180,
},
select: {
padding: '0 4em',
},
}))
export default function Welcome({ next, identities, didntFindAccount }: Props) {
const classes = useStyles()
const [selected, setSelect] = useState<Person[]>([])
return (
<WelcomeContainer className={classes.paper}>
<Typography variant="h5">{geti18nString('welcome_1a1_title')}</Typography>
<SelectPeopleUI
classes={{ root: classes.select }}
hideSelectAll
hideSelectNone
showAtNetwork
maxSelection={1}
people={identities}
selected={[]}
frozenSelected={selected}
onSetSelected={setSelect}
/>
<Button
disabled={selected.length === 0}
onClick={() => next(selected[0])}
variant="contained"
color="primary"
className={classes.button}>
{geti18nString('welcome_1a1_next')}
</Button>
<br />
<Button onClick={didntFindAccount} color="primary">
{geti18nString('welcome_1a1_didntfind')}
</Button>
</WelcomeContainer>
)
}
2 changes: 1 addition & 1 deletion src/extension/options-page/Welcome/index.tsx
Expand Up @@ -127,7 +127,7 @@ function Welcome(props: Welcome) {
return <Welcome2 />
}
}
const ResponsiveDialog = withMobileDialog()(Dialog)
const ResponsiveDialog = withMobileDialog({ breakpoint: 'xs' })(Dialog)
const ProvePostRef = new ValueRef('')
const IdentifierRef = new ValueRef(PersonIdentifier.unknown)
const getMyProveBio = async () => {
Expand Down
15 changes: 13 additions & 2 deletions src/stories/Welcome.tsx
@@ -1,6 +1,7 @@
import React from 'react'
import { storiesOf } from '@storybook/react'
import Welcome0 from '../components/Welcomes/0'
import Welcome1a1 from '../components/Welcomes/1a1'
import Welcome1a2 from '../components/Welcomes/1a2'
import Welcome1a3 from '../components/Welcomes/1a3'
import Welcome1a4v2 from '../components/Welcomes/1a4.v2'
Expand All @@ -12,8 +13,9 @@ import { action } from '@storybook/addon-actions'
import { BannerUI } from '../components/Welcomes/Banner'
import { withMobileDialog, Dialog } from '@material-ui/core'
import QRScanner from '../components/Welcomes/QRScanner'
import { demoPeople } from './demoPeople'

const ResponsiveDialog = withMobileDialog()(Dialog)
const ResponsiveDialog = withMobileDialog({ breakpoint: 'xs' })(Dialog)
storiesOf('Welcome', module)
.add('Banner', () => (
<BannerUI disabled={boolean('disabled', false)} close={action('Close')} getStarted={to('Welcome', 'Step 0')} />
Expand All @@ -22,11 +24,20 @@ storiesOf('Welcome', module)
<ResponsiveDialog open>
<Welcome0
close={action('Close')}
create={to('Welcome', 'Step 1a-2')}
create={to('Welcome', 'Step 1a-1')}
restore={to('Welcome', 'Step 1b-1')}
/>
</ResponsiveDialog>
))
.add('Step 1a-1', () => (
<ResponsiveDialog open>
<Welcome1a1
next={() => to('Welcome', 'Step 1a-2')}
identities={demoPeople}
didntFindAccount={action('didntFindAccount')}
/>
</ResponsiveDialog>
))
.add('Step 1a-2', () => (
<ResponsiveDialog open>
<Welcome1a2 next={to('Welcome', 'Step 1a-3')} />
Expand Down

0 comments on commit fa5ba06

Please sign in to comment.