Skip to content
Merged
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
1 change: 1 addition & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
}
},
"rules": {
"no-alert": "error",
"sort-class-members/sort-class-members": [
"error",
{
Expand Down
3 changes: 2 additions & 1 deletion packages/components/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
{
"files": ["**/*.stories.tsx"],
"rules": {
"import/no-default-export": "off"
"import/no-default-export": "off",
"no-alert": "off"
}
}
]
Expand Down
46 changes: 45 additions & 1 deletion packages/cypress/src/integration/settings.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ describe('[Settings]', () => {
.click()
}

const addContactLink = (link: ILink) => {
const addContactLink = (link: Omit<ILink, 'key'>) => {
if (link.index > 0) {
// click the button to add another set of input fields
cy.get('[data-cy=add-link]').click()
Expand Down Expand Up @@ -359,6 +359,50 @@ describe('[Settings]', () => {
.should('eqSettings', expected)
})
})

it('[Edit Contact and Links]', () => {
cy.login('settings_member_new@test.com', 'test1234')
cy.step('Go to User Settings')
cy.clickMenuItem(UserMenuItem.Settings)

addContactLink({
index: 1,
label: 'social',
url: 'https://social.network',
})

// Remove first item
cy.get('[data-cy="delete-link-0"]').last().trigger('click')

cy.get('[data-cy="Link.field: Modal"]').should('be.visible')

cy.get('[data-cy="Link.field: Delete"]').trigger('click')

cy.get('[data-cy=save]').click()
cy.get('[data-cy=save]').should('not.be.disabled')

// Assert
cy.queryDocuments(
DbCollectionName.users,
'userName',
'==',
expected.userName,
).then((docs) => {
cy.log('queryDocs', docs)
expect(docs.length).to.equal(1)
cy.wrap(null)
.then(() => docs[0])
.should('eqSettings', {
...expected,
links: [
{
label: 'social',
url: 'https://social.network',
},
],
})
})
})
})

describe('[Focus Machine Builder]', () => {
Expand Down
1 change: 1 addition & 0 deletions src/models/user.models.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export interface IUserBadges {
}

interface IExternalLink {
key: string
url: string
label:
| 'email'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export const HowToComments = ({ comments }: IProps) => {
}

async function handleDelete(_id: string) {
// eslint-disable-next-line no-alert
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: are we planning on making these into custom modals down the line?

const confirmation = window.confirm(
'Are you sure you want to delete this comment?',
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export const ResearchComments = ({
}

async function handleDelete(_id: string) {
// eslint-disable-next-line no-alert
const confirmation = window.confirm(
'Are you sure you want to delete this comment?',
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

Expand Down
6 changes: 5 additions & 1 deletion src/pages/Settings/SettingsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { logger } from 'src/logger'
import { ProfileType } from 'src/modules/profile/types'
import { AuthWrapper } from 'src/common/AuthWrapper'
import { UnsavedChangesDialog } from 'src/common/Form/UnsavedChangesDialog'
import { v4 as uuid } from 'uuid'

interface IProps {
/** user ID for lookup when editing another user as admin */
Expand Down Expand Up @@ -86,7 +87,10 @@ export class UserSettings extends React.Component<IProps, IState> {
coverImages: new Array(4)
.fill(null)
.map((v, i) => (coverImages[i] ? coverImages[i] : v)),
links: links.length > 0 ? links : [{} as any],
links: (links.length > 0 ? links : [{} as any]).map((i) => ({
...i,
key: uuid(),
})),
openingHours: openingHours!.length > 0 ? openingHours : [{} as any],
}
this.setState({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Component } from 'react'
import { Field } from 'react-final-form'
import { Button, FieldInput, Modal } from 'oa-components'
import { Text, Flex, Grid } from 'theme-ui'
import { Text, Flex, Grid, Box } from 'theme-ui'
import { SelectField } from 'src/common/Form/Select.field'
import { validateUrl, validateEmail, required } from 'src/utils/validators'
import { formatLink } from 'src/utils/formatters'
Expand Down Expand Up @@ -31,7 +31,9 @@ interface IProps {
initialType?: string
onDelete: () => void
'data-cy'?: string
isDeleteEnabled: boolean
}

interface IState {
showDeleteModal: boolean
_toDocsList: boolean
Expand Down Expand Up @@ -74,7 +76,7 @@ export class ProfileLinkField extends Component<IProps, IState> {
}

render() {
const { index, name } = this.props
const { index, name, isDeleteEnabled } = this.props
const DeleteButton = (props) => (
<Button
data-cy={`delete-link-${index}`}
Expand All @@ -84,20 +86,18 @@ export class ProfileLinkField extends Component<IProps, IState> {
onClick={() => this.toggleDeleteModal()}
ml={2}
{...props}
/>
>
Delete
</Button>
)
return (
<Flex
my={['10px', '10px', '5px']}
sx={{ flexDirection: ['column', 'column', 'row'] }}
>
<Grid
mb={[1, 1, 0]}
gap={0}
columns={['auto 60px', 'auto 60px', '210px']}
sx={{ width: ['100%', '100%', '210px'] }}
>
<div>
<Flex my={[2]} sx={{ flexDirection: ['column', 'column', 'row'] }}>
<Grid mb={[1, 1, 0]} gap={0} sx={{ width: ['100%', '100%', '210px'] }}>
<Box
sx={{
mr: 2,
}}
>
<Field
data-cy={`select-link-${index}`}
name={`${name}.label`}
Expand All @@ -107,23 +107,23 @@ export class ProfileLinkField extends Component<IProps, IState> {
placeholder="type"
validate={required}
validateFields={[]}
style={{ width: '100%', height: '40px', marginRight: '8px' }}
style={{ width: '100%', height: '40px' }}
/>
</div>
<DeleteButton
sx={{
display: ['block', 'block', 'none'],
height: '40px',
width: '50px',
}}
ml={'2px'}
/>
</Box>
{isDeleteEnabled ? (
<DeleteButton
sx={{
display: ['block', 'block', 'none'],
}}
ml={'2px'}
/>
) : null}
</Grid>
<Grid
mb={[1, 1, 0]}
gap={0}
columns={['auto', 'auto', 'auto']}
sx={{ width: ['100%', '100%', 'calc(100% - 270px)'] }}
sx={{ width: '100%' }}
>
<Field
data-cy={`input-link-${index}`}
Expand All @@ -137,37 +137,40 @@ export class ProfileLinkField extends Component<IProps, IState> {
style={{ width: '100%', height: '40px', marginBottom: '0px' }}
/>
</Grid>
<DeleteButton
sx={{
display: ['none', 'none', 'block'],
height: '40px',
width: '50px',
}}
/>
{isDeleteEnabled ? (
<DeleteButton
sx={{
display: ['none', 'none', 'block'],
}}
/>
) : null}
{
<Modal
onDidDismiss={() => this.toggleDeleteModal()}
isOpen={!!this.state.showDeleteModal}
>
<Text>Are you sure you want to delete this link?</Text>
<Flex p={0} mx={-1} sx={{ justifyContent: 'flex-end' }}>
<Flex px={1}>
<Button
variant={'outline'}
onClick={() => this.toggleDeleteModal()}
>
Cancel
</Button>
</Flex>
<Flex px={1}>
<Button
variant={'outline'}
onClick={() => this.confirmDelete()}
>
Delete
</Button>
<Box data-cy="Link.field: Modal">
<Text>Are you sure you want to delete this link?</Text>
<Flex p={0} mx={-1} sx={{ justifyContent: 'flex-end' }}>
<Flex px={1}>
<Button
variant={'outline'}
onClick={() => this.toggleDeleteModal()}
>
Cancel
</Button>
</Flex>
<Flex px={1}>
<Button
data-cy="Link.field: Delete"
variant={'outline'}
onClick={() => this.confirmDelete()}
>
Delete
</Button>
</Flex>
</Flex>
</Flex>
</Box>
</Modal>
}
</Flex>
Expand Down
29 changes: 16 additions & 13 deletions src/pages/Settings/content/formSections/UserInfos.section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { countries } from 'countries-list'
import { Button, FieldInput, FieldTextarea } from 'oa-components'
import theme from 'src/themes/styled.theme'
import { FieldArray } from 'react-final-form-arrays'
import { ProfileLinkField } from './Fields/Link.field'
import { ProfileLinkField } from './Fields/ProfileLink.field'
import { FlexSectionContainer } from './elements'
import { required } from 'src/utils/validators'
import type { IUserPP } from 'src/models/user_pp.models'
Expand Down Expand Up @@ -190,7 +190,7 @@ export class UserInfosSection extends React.Component<IProps, IState> {
coverImages={coverImages}
/>
</Flex>
<>
<Box data-cy="UserInfos: links">
<Flex sx={{ alignItems: 'center', width: '100%', wrap: 'nowrap' }}>
<Text mb={2} mt={7} sx={{ fontSize: 2 }}>
Contacts & links *
Expand All @@ -199,16 +199,19 @@ export class UserInfosSection extends React.Component<IProps, IState> {
<FieldArray name="links" initialValue={links}>
{({ fields }) => (
<>
{fields.map((name, i: number) => (
<ProfileLinkField
key={name}
name={name}
onDelete={() => {
fields.remove(i)
}}
index={i}
/>
))}
{fields
? fields.map((name, i: number) => (
<ProfileLinkField
key={fields.value[i].key}
name={name}
onDelete={() => {
fields.remove(i)
}}
index={i}
isDeleteEnabled={i > 0 || (fields as any).length > 1}
/>
))
: null}
<Button
type="button"
data-cy="add-link"
Expand All @@ -223,7 +226,7 @@ export class UserInfosSection extends React.Component<IProps, IState> {
</>
)}
</FieldArray>
</>
</Box>
</Box>
</FlexSectionContainer>
)
Expand Down