Skip to content

Commit cd298d4

Browse files
authored
Merge branch 'develop' into new-password-error
2 parents f3f27ea + 8f4b9fd commit cd298d4

File tree

11 files changed

+277
-121
lines changed

11 files changed

+277
-121
lines changed

client/modules/IDE/components/CollectionList/CollectionListRow.jsx

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,88 @@ import { connect } from 'react-redux';
44
import { Link } from 'react-router-dom';
55
import { bindActionCreators } from 'redux';
66
import { withTranslation } from 'react-i18next';
7+
import styled from 'styled-components';
78
import MenuItem from '../../../../components/Dropdown/MenuItem';
89
import TableDropdown from '../../../../components/Dropdown/TableDropdown';
910
import * as ProjectActions from '../../actions/project';
1011
import * as CollectionsActions from '../../actions/collections';
1112
import * as IdeActions from '../../actions/ide';
1213
import * as ToastActions from '../../actions/toast';
1314
import dates from '../../../../utils/formatDate';
15+
import { remSize, prop } from '../../../../theme';
1416

17+
const SketchsTableRow = styled.tr`
18+
&&& {
19+
margin: ${remSize(10)};
20+
height: ${remSize(72)};
21+
font-size: ${remSize(16)};
22+
}
23+
&:nth-child(odd) {
24+
background: ${prop('tableRowStripeColor')};
25+
}
26+
27+
> th:nth-child(1) {
28+
padding-left: ${remSize(12)};
29+
}
30+
31+
> td {
32+
padding-left: ${remSize(8)};
33+
}
34+
35+
a {
36+
color: ${prop('primaryTextColor')};
37+
}
38+
39+
&.is-deleted > * {
40+
font-style: italic;
41+
}
42+
@media (max-width: 770px) {
43+
&&& {
44+
margin: 0;
45+
position: relative;
46+
display: flex;
47+
flex-wrap: wrap;
48+
padding: ${remSize(15)};
49+
height: fit-content;
50+
gap: ${remSize(8)};
51+
border: 1px solid ${prop('modalBorderColor')};
52+
background-color: ${prop('searchBackgroundColor')};
53+
> th {
54+
padding-left: 0;
55+
width: 100%;
56+
font-weight: bold;
57+
margin-bottom: ${remSize(6)};
58+
}
59+
> td {
60+
padding-left: 0;
61+
width: 30%;
62+
font-size: ${remSize(14)};
63+
color: ${prop('modalBorderColor')};
64+
}
65+
}
66+
}
67+
`;
68+
const SketchesTableName = styled.span`
69+
&&& {
70+
display: flex;
71+
align-items: center;
72+
}
73+
`;
74+
const SketchlistDropdownColumn = styled.td`
75+
&&& {
76+
position: relative;
77+
width: ${remSize(60)};
78+
}
79+
@media (max-width: 770px) {
80+
&&& {
81+
position: absolute;
82+
top: 0;
83+
right: ${remSize(4)};
84+
width: auto !important;
85+
margin: ${remSize(8)};
86+
}
87+
}
88+
`;
1589
const formatDateCell = (date, mobile = false) =>
1690
dates.format(date, { showTime: !mobile });
1791

@@ -126,18 +200,18 @@ const CollectionListRowBase = (props) => {
126200
const { collection, mobile } = props;
127201

128202
return (
129-
<tr className="sketches-table__row" key={collection.id}>
203+
<SketchsTableRow key={collection.id}>
130204
<th scope="row">
131-
<span className="sketches-table__name">{renderCollectionName()}</span>
205+
<SketchesTableName>{renderCollectionName()}</SketchesTableName>
132206
</th>
133207
<td>{formatDateCell(collection.createdAt, mobile)}</td>
134208
<td>{formatDateCell(collection.updatedAt, mobile)}</td>
135209
<td>
136210
{mobile && 'sketches: '}
137211
{(collection.items || []).length}
138212
</td>
139-
<td className="sketch-list__dropdown-column">{renderActions()}</td>
140-
</tr>
213+
<SketchlistDropdownColumn>{renderActions()}</SketchlistDropdownColumn>
214+
</SketchsTableRow>
141215
);
142216
};
143217

client/modules/IDE/components/FileNode.jsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,11 +187,19 @@ class FileNode extends React.Component {
187187
if (
188188
hasEmptyFilename ||
189189
hasNoExtension ||
190-
notSameExtension ||
191190
hasOnlyExtension ||
192191
hasExtensionIfFolder
193192
) {
194193
this.setUpdatedName(currentName);
194+
} else if (notSameExtension) {
195+
const userResponse = window.confirm(
196+
'Are you sure you want to change the file extension?'
197+
);
198+
if (userResponse) {
199+
this.saveUpdatedFileName();
200+
} else {
201+
this.setUpdatedName(currentName);
202+
}
195203
} else {
196204
this.saveUpdatedFileName();
197205
}

client/modules/IDE/components/NewFileForm.jsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,15 @@ function NewFileForm() {
5555
</React.Fragment>
5656
)}
5757
</Field>
58-
<Button type="submit" disabled={invalid || submitting}>
59-
{t('NewFileForm.AddFileSubmit')}
60-
</Button>
58+
<Field name="submitButton">
59+
{() => (
60+
<Button type="submit" disabled={submitting}>
61+
{t('NewFileForm.AddFileSubmit')}
62+
</Button>
63+
)}
64+
</Field>
6165
</div>
62-
{touched.name && errors.name && (
66+
{touched.submitButton && errors.name && (
6367
<span className="form-error">{errors.name}</span>
6468
)}
6569
</form>

client/modules/IDE/components/NewFolderForm.jsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,15 @@ function NewFolderForm() {
5252
</React.Fragment>
5353
)}
5454
</Field>
55-
<Button type="submit" disabled={invalid || submitting}>
56-
{t('NewFolderForm.AddFolderSubmit')}
57-
</Button>
55+
<Field name="submitButton">
56+
{() => (
57+
<Button type="submit" disabled={submitting}>
58+
{t('NewFolderForm.AddFolderSubmit')}
59+
</Button>
60+
)}
61+
</Field>
5862
</div>
59-
{touched.name && errors.name && (
63+
{touched.submitButton && errors.name && (
6064
<span className="form-error">{errors.name}</span>
6165
)}
6266
</form>

client/modules/IDE/components/Searchbar/Searchbar.jsx

Lines changed: 47 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,65 @@
1+
import React, { useState, useCallback, useEffect } from 'react';
12
import PropTypes from 'prop-types';
2-
import React from 'react';
33
import { throttle } from 'lodash';
44
import { withTranslation } from 'react-i18next';
55
import i18next from 'i18next';
66
import SearchIcon from '../../../../images/magnifyingglass.svg';
77

8-
class Searchbar extends React.Component {
9-
constructor(props) {
10-
super(props);
11-
this.state = {
12-
searchValue: this.props.searchTerm
13-
};
14-
this.throttledSearchChange = throttle(this.searchChange, 500);
15-
}
8+
const Searchbar = ({
9+
searchTerm,
10+
setSearchTerm,
11+
resetSearchTerm,
12+
searchLabel,
13+
t
14+
}) => {
15+
const [searchValue, setSearchValue] = useState(searchTerm);
1616

17-
componentWillUnmount() {
18-
this.props.resetSearchTerm();
19-
}
17+
const throttledSearchChange = useCallback(
18+
throttle((value) => {
19+
setSearchTerm(value.trim());
20+
}, 500),
21+
[]
22+
);
2023

21-
handleResetSearch = () => {
22-
this.setState({ searchValue: '' }, () => {
23-
this.props.resetSearchTerm();
24-
});
24+
const handleResetSearch = () => {
25+
setSearchValue('');
26+
resetSearchTerm();
2527
};
2628

27-
searchChange = () => {
28-
this.props.setSearchTerm(this.state.searchValue.trim());
29+
const handleSearchChange = (e) => {
30+
const { value } = e.target;
31+
setSearchValue(value);
32+
throttledSearchChange(value.trim());
2933
};
3034

31-
handleSearchChange = (e) => {
32-
this.setState({ searchValue: e.target.value }, () => {
33-
this.throttledSearchChange(this.state.searchValue.trim());
34-
});
35-
};
35+
useEffect(() => {
36+
setSearchValue(searchTerm);
37+
}, [searchTerm]);
3638

37-
render() {
38-
const { searchValue } = this.state;
39-
return (
40-
<div
41-
className={`searchbar ${
42-
searchValue === '' ? 'searchbar--is-empty' : ''
43-
}`}
44-
>
45-
<div className="searchbar__button">
46-
<SearchIcon
47-
className="searchbar__icon"
48-
focusable="false"
49-
aria-hidden="true"
50-
/>
51-
</div>
52-
<input
53-
className="searchbar__input"
54-
type="text"
55-
value={searchValue}
56-
placeholder={this.props.searchLabel}
57-
onChange={this.handleSearchChange}
39+
return (
40+
<div
41+
className={`searchbar ${searchValue === '' ? 'searchbar--is-empty' : ''}`}
42+
>
43+
<div className="searchbar__button">
44+
<SearchIcon
45+
className="searchbar__icon"
46+
focusable="false"
47+
aria-hidden="true"
5848
/>
59-
<button
60-
className="searchbar__clear-button"
61-
onClick={this.handleResetSearch}
62-
>
63-
{this.props.t('Searchbar.ClearTerm')}
64-
</button>
6549
</div>
66-
);
67-
}
68-
}
50+
<input
51+
className="searchbar__input"
52+
type="text"
53+
value={searchValue}
54+
placeholder={searchLabel}
55+
onChange={handleSearchChange}
56+
/>
57+
<button className="searchbar__clear-button" onClick={handleResetSearch}>
58+
{t('Searchbar.ClearTerm')}
59+
</button>
60+
</div>
61+
);
62+
};
6963

7064
Searchbar.propTypes = {
7165
searchTerm: PropTypes.string.isRequired,

client/modules/User/components/LoginForm.jsx

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import React from 'react';
1+
import React, { useState } from 'react';
22
import { useTranslation } from 'react-i18next';
33
import { Form, Field } from 'react-final-form';
44
import { useDispatch } from 'react-redux';
5+
import { AiOutlineEye, AiOutlineEyeInvisible } from 'react-icons/ai';
56
import Button from '../../../common/Button';
67
import { validateLogin } from '../../../utils/reduxFormUtils';
78
import { validateAndLoginUser } from '../actions';
@@ -13,6 +14,10 @@ function LoginForm() {
1314
function onSubmit(formProps) {
1415
return dispatch(validateAndLoginUser(formProps));
1516
}
17+
const [showPassword, setShowPassword] = useState(false);
18+
const handleVisibility = () => {
19+
setShowPassword(!showPassword);
20+
};
1621

1722
return (
1823
<Form
@@ -45,22 +50,35 @@ function LoginForm() {
4550
</Field>
4651
<Field name="password">
4752
{(field) => (
48-
<p className="form__field">
49-
<label htmlFor="password" className="form__label">
50-
{t('LoginForm.Password')}
51-
</label>
52-
<input
53-
className="form__input"
54-
aria-label={t('LoginForm.PasswordARIA')}
55-
type="password"
56-
id="password"
57-
autoComplete="current-password"
58-
{...field.input}
59-
/>
60-
{field.meta.touched && field.meta.error && (
61-
<span className="form-error">{field.meta.error}</span>
62-
)}
63-
</p>
53+
<div>
54+
<p className="form__field">
55+
<label htmlFor="password" className="form__label">
56+
{t('LoginForm.Password')}
57+
</label>
58+
<button
59+
className="form__eye__icon"
60+
type="button"
61+
onClick={handleVisibility}
62+
>
63+
{showPassword ? (
64+
<AiOutlineEyeInvisible />
65+
) : (
66+
<AiOutlineEye />
67+
)}
68+
</button>
69+
<input
70+
className="form__input"
71+
aria-label={t('LoginForm.PasswordARIA')}
72+
type={showPassword ? 'text' : 'password'}
73+
id="password"
74+
autoComplete="current-password"
75+
{...field.input}
76+
/>
77+
{field.meta.touched && field.meta.error && (
78+
<span className="form-error">{field.meta.error}</span>
79+
)}
80+
</p>
81+
</div>
6482
)}
6583
</Field>
6684
{submitError && !modifiedSinceLastSubmit && (

0 commit comments

Comments
 (0)