Skip to content

Commit cae1399

Browse files
committed
backend done, frontend progress
1 parent 73ce9f7 commit cae1399

File tree

18 files changed

+347
-52
lines changed

18 files changed

+347
-52
lines changed

client/constants.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export const DELETE_COLLECTION = 'DELETE_COLLECTION';
4141
export const ADD_TO_COLLECTION = 'ADD_TO_COLLECTION';
4242
export const REMOVE_FROM_COLLECTION = 'REMOVE_FROM_COLLECTION';
4343
export const EDIT_COLLECTION = 'EDIT_COLLECTION';
44+
export const CHANGE_VISIBILITY = 'CHANGE_VISIBILITY';
4445

4546
export const DELETE_PROJECT = 'DELETE_PROJECT';
4647

client/modules/IDE/actions/project.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,3 +410,27 @@ export function deleteProject(id) {
410410
});
411411
};
412412
}
413+
414+
export function changeVisibility(projectId, visibility) {
415+
return (dispatch) =>
416+
apiClient
417+
.patch('/project/visibility', { projectId, visibility })
418+
.then((response) => {
419+
console.log(response.data);
420+
const { visibility: newVisibility } = response.data;
421+
422+
dispatch({
423+
type: ActionTypes.CHANGE_VISIBILITY,
424+
payload: { visibility: response.data.visibility }
425+
});
426+
427+
dispatch(setToastText(`Sketch is switched to ${newVisibility}`));
428+
dispatch(showToast(2000));
429+
})
430+
.catch((error) => {
431+
dispatch({
432+
type: ActionTypes.ERROR,
433+
error: error?.response?.data
434+
});
435+
});
436+
}

client/modules/IDE/components/Header/Toolbar.jsx

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import PlayIcon from '../../../../images/play.svg';
2020
import StopIcon from '../../../../images/stop.svg';
2121
import PreferencesIcon from '../../../../images/preferences.svg';
2222
import ProjectName from './ProjectName';
23+
import { changeVisibility } from '../../actions/project';
24+
import Button from '../../../../common/Button';
2325

2426
const Toolbar = (props) => {
2527
const { isPlaying, infiniteLoop, preferencesIsVisible } = useSelector(
@@ -28,8 +30,22 @@ const Toolbar = (props) => {
2830
const project = useSelector((state) => state.project);
2931
const autorefresh = useSelector((state) => state.preferences.autorefresh);
3032
const dispatch = useDispatch();
31-
3233
const { t } = useTranslation();
34+
const [visibility, setVisibility] = React.useState(project.visibility);
35+
console.log(project);
36+
const toggleVisibility = () => {
37+
try {
38+
setVisibility((prev) => (prev === 'Public' ? 'Private' : 'Public'));
39+
dispatch(
40+
changeVisibility(
41+
project.id,
42+
visibility === 'Public' ? 'Private' : 'Public'
43+
)
44+
);
45+
} catch (error) {
46+
console.log(error);
47+
}
48+
};
3349

3450
const playButtonClass = classNames({
3551
'toolbar__play-button': true,
@@ -112,6 +128,15 @@ const Toolbar = (props) => {
112128
return null;
113129
})()}
114130
</div>
131+
{project?.owner && (
132+
<section>
133+
{visibility === 'Private' ? (
134+
<Button onClick={toggleVisibility}>Private</Button>
135+
) : (
136+
<Button onClick={toggleVisibility}>Public</Button>
137+
)}
138+
</section>
139+
)}
115140
<button
116141
className={preferencesButtonClass}
117142
onClick={() => dispatch(openPreferences())}

client/modules/IDE/components/SketchList.jsx

Lines changed: 86 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import getConfig from '../../../utils/getConfig';
2424

2525
import ArrowUpIcon from '../../../images/sort-arrow-up.svg';
2626
import ArrowDownIcon from '../../../images/sort-arrow-down.svg';
27+
import Button from '../../../common/Button';
2728

2829
const ROOT_URL = getConfig('API_URL');
2930

@@ -35,11 +36,24 @@ class SketchListRowBase extends React.Component {
3536
super(props);
3637
this.state = {
3738
renameOpen: false,
38-
renameValue: props.sketch.name
39+
renameValue: props.sketch.name,
40+
newVisibility: props.sketch.visibility || 'Public',
41+
visibleDialogOpen: false
3942
};
4043
this.renameInput = React.createRef();
4144
}
4245

46+
toggleVisibility = () => {
47+
this.setState((prev) => ({
48+
newVisibility: prev.newVisibility === 'Public' ? 'Private' : 'Public'
49+
}));
50+
this.props.changeVisibility(
51+
this.props.sketch.id,
52+
this.state.newVisibility === 'Public' ? 'Private' : 'Public'
53+
);
54+
this.setState({ visibleDialogOpen: false });
55+
};
56+
4357
openRename = () => {
4458
this.setState(
4559
{
@@ -136,6 +150,12 @@ class SketchListRowBase extends React.Component {
136150
>
137151
{this.props.t('SketchList.DropdownDuplicate')}
138152
</MenuItem>
153+
<MenuItem
154+
hideIf={!userIsOwner}
155+
onClick={() => this.setState({ visibleDialogOpen: true })}
156+
>
157+
Change Visibility
158+
</MenuItem>
139159
<MenuItem
140160
hideIf={!this.props.user.authenticated}
141161
onClick={() => {
@@ -159,12 +179,21 @@ class SketchListRowBase extends React.Component {
159179
};
160180

161181
render() {
182+
console.log(this.props.sketch.visibility);
162183
const { sketch, username, mobile } = this.props;
163184
const { renameOpen, renameValue } = this.state;
164185
let url = `/${username}/sketches/${sketch.id}`;
165186
if (username === 'p5') {
166187
url = `/${username}/sketches/${slugify(sketch.name, '_')}`;
167188
}
189+
const title = (
190+
<p>
191+
Make {this.props.sketch.name}
192+
<span className="sketch-visibility__title">
193+
{this.state.newVisibility === 'Private' ? 'Public' : 'Private'}
194+
</span>
195+
</p>
196+
);
168197

169198
const name = (
170199
<React.Fragment>
@@ -179,6 +208,33 @@ class SketchListRowBase extends React.Component {
179208
ref={this.renameInput}
180209
/>
181210
)}
211+
212+
{this.state.visibleDialogOpen && (
213+
<Overlay
214+
title={title}
215+
closeOverlay={() => this.setState({ visibleDialogOpen: false })}
216+
>
217+
<div className="sketch-visibility">
218+
<hr />
219+
220+
<ul>
221+
<li>The sketch will not be visible to others.</li>
222+
<li>
223+
Other users will not be able to fork, edit or look the sketch
224+
</li>
225+
<li>
226+
You can always comeback and change the sketchs visibility
227+
nonetheless
228+
</li>
229+
</ul>
230+
231+
<hr />
232+
<Button onClick={this.toggleVisibility}>
233+
I have read and understand these effects
234+
</Button>
235+
</div>
236+
</Overlay>
237+
)}
182238
</React.Fragment>
183239
);
184240

@@ -189,7 +245,11 @@ class SketchListRowBase extends React.Component {
189245
key={sketch.id}
190246
onClick={this.handleRowClick}
191247
>
192-
<th scope="row">{name}</th>
248+
<th scope="row" className="sketches-table__rowname">
249+
{this.state.newVisibility === 'Private' && <p>Lock</p>}
250+
{this.state.newVisibility}
251+
{name}
252+
</th>
193253
<td>{formatDateCell(sketch.createdAt, mobile)}</td>
194254
<td>{formatDateCell(sketch.updatedAt, mobile)}</td>
195255
{this.renderDropdown()}
@@ -204,7 +264,8 @@ SketchListRowBase.propTypes = {
204264
id: PropTypes.string.isRequired,
205265
name: PropTypes.string.isRequired,
206266
createdAt: PropTypes.string.isRequired,
207-
updatedAt: PropTypes.string.isRequired
267+
updatedAt: PropTypes.string.isRequired,
268+
visibility: PropTypes.string
208269
}).isRequired,
209270
username: PropTypes.string.isRequired,
210271
user: PropTypes.shape({
@@ -216,6 +277,7 @@ SketchListRowBase.propTypes = {
216277
cloneProject: PropTypes.func.isRequired,
217278
changeProjectName: PropTypes.func.isRequired,
218279
onAddToCollection: PropTypes.func.isRequired,
280+
changeVisibility: PropTypes.func.isRequired,
219281
mobile: PropTypes.bool,
220282
t: PropTypes.func.isRequired
221283
};
@@ -241,7 +303,6 @@ class SketchList extends React.Component {
241303
super(props);
242304
this.props.getProjects(this.props.username);
243305
this.props.resetSorting();
244-
245306
this.state = {
246307
isInitialDataLoad: true
247308
};
@@ -354,6 +415,8 @@ class SketchList extends React.Component {
354415
};
355416

356417
render() {
418+
const userIsOwner = this.props.user.username === this.props.username;
419+
357420
const username =
358421
this.props.username !== undefined
359422
? this.props.username
@@ -393,19 +456,23 @@ class SketchList extends React.Component {
393456
</tr>
394457
</thead>
395458
<tbody>
396-
{this.props.sketches.map((sketch) => (
397-
<SketchListRow
398-
mobile={mobile}
399-
key={sketch.id}
400-
sketch={sketch}
401-
user={this.props.user}
402-
username={username}
403-
onAddToCollection={() => {
404-
this.setState({ sketchToAddToCollection: sketch });
405-
}}
406-
t={this.props.t}
407-
/>
408-
))}
459+
{this.props.sketches
460+
.filter(
461+
(sketch) => userIsOwner || sketch.visibility === 'Public'
462+
)
463+
.map((sketch) => (
464+
<SketchListRow
465+
mobile={mobile}
466+
key={sketch.id}
467+
sketch={sketch}
468+
user={this.props.user}
469+
username={username}
470+
onAddToCollection={() => {
471+
this.setState({ sketchToAddToCollection: sketch });
472+
}}
473+
t={this.props.t}
474+
/>
475+
))}
409476
</tbody>
410477
</table>
411478
)}
@@ -438,7 +505,8 @@ SketchList.propTypes = {
438505
id: PropTypes.string.isRequired,
439506
name: PropTypes.string.isRequired,
440507
createdAt: PropTypes.string.isRequired,
441-
updatedAt: PropTypes.string.isRequired
508+
updatedAt: PropTypes.string.isRequired,
509+
visibility: PropTypes.string
442510
})
443511
).isRequired,
444512
username: PropTypes.string,

client/modules/IDE/reducers/project.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ const initialState = () => {
88
return {
99
name: generatedName,
1010
updatedAt: '',
11-
isSaving: false
11+
isSaving: false,
12+
visibility: 'Public'
1213
};
1314
};
1415

@@ -25,15 +26,17 @@ const project = (state, action) => {
2526
name: action.project.name,
2627
updatedAt: action.project.updatedAt,
2728
owner: action.owner,
28-
isSaving: false
29+
isSaving: false,
30+
visibility: action.project.visibility
2931
};
3032
case ActionTypes.SET_PROJECT:
3133
return {
3234
id: action.project.id,
3335
name: action.project.name,
3436
updatedAt: action.project.updatedAt,
3537
owner: action.owner,
36-
isSaving: false
38+
isSaving: false,
39+
visibility: action.project.visibility
3740
};
3841
case ActionTypes.RESET_PROJECT:
3942
return initialState();

client/modules/IDE/reducers/projects.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ const sketches = (state = [], action) => {
66
return action.projects;
77
case ActionTypes.DELETE_PROJECT:
88
return state.filter((sketch) => sketch.id !== action.id);
9+
case ActionTypes.CHANGE_VISIBILITY:
10+
return state.map((sketch) => ({
11+
...sketch,
12+
visibility: action.payload.visibility
13+
}));
914
case ActionTypes.RENAME_PROJECT: {
1015
return state.map((sketch) => {
1116
if (sketch.id === action.payload.id) {

client/modules/User/components/Collection.jsx

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ const CollectionItemRowBase = ({
3232

3333
const projectIsDeleted = item.isDeleted;
3434

35+
const projectIsPrivate = !isOwner && item.project.visibility === 'Private';
36+
3537
const handleSketchRemove = () => {
3638
const name = projectIsDeleted ? 'deleted sketch' : item.project.name;
3739

@@ -44,13 +46,18 @@ const CollectionItemRowBase = ({
4446
}
4547
};
4648

47-
const name = projectIsDeleted ? (
48-
<span>{t('Collection.SketchDeleted')}</span>
49-
) : (
50-
<Link to={`/${item.project.user.username}/sketches/${item.projectId}`}>
51-
{item.project.name}
52-
</Link>
53-
);
49+
let name;
50+
if (projectIsDeleted) {
51+
name = <span>{t('Collection.SketchDeleted')}</span>;
52+
} else if (projectIsPrivate) {
53+
name = <span>Project is Private</span>;
54+
} else {
55+
name = (
56+
<Link to={`/${item.project.user.username}/sketches/${item.projectId}`}>
57+
{item.project.name}
58+
</Link>
59+
);
60+
}
5461

5562
const sketchOwnerUsername = projectIsDeleted
5663
? null
@@ -90,6 +97,7 @@ CollectionItemRowBase.propTypes = {
9097
project: PropTypes.shape({
9198
id: PropTypes.string.isRequired,
9299
name: PropTypes.string.isRequired,
100+
visibility: PropTypes.string,
93101
user: PropTypes.shape({
94102
username: PropTypes.string.isRequired
95103
})

0 commit comments

Comments
 (0)