Skip to content

Commit 34af957

Browse files
authored
Merge pull request #181 from canyener/add-loading-indicator-for-submitting
Add loading indicator for submitting
2 parents 7733216 + 52a0845 commit 34af957

File tree

11 files changed

+97
-17
lines changed

11 files changed

+97
-17
lines changed

src/app/layout/App.tsx

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState, useEffect, Fragment } from 'react'
1+
import React, { useState, useEffect, Fragment, SyntheticEvent } from 'react'
22
import { Container } from 'semantic-ui-react'
33

44
import { IActivity } from '../models/activity'
@@ -14,6 +14,8 @@ const App = () => {
1414
const [selectedActivity, setSelectedActivity] = useState<IActivity | null>(null)
1515
const [editMode, setEditMode] = useState(false)
1616
const [loading, setLoading] = useState(true)
17+
const [submitting, setSubmitting] = useState(false)
18+
const [target, setTarget] = useState('')
1719

1820
const handleSelectActivity = (id: string) => {
1921
setSelectedActivity(activities.filter(activity => activity.id === id)[0])
@@ -26,25 +28,32 @@ const App = () => {
2628
}
2729

2830
const handleCreateActivity = (activity: IActivity) => {
31+
setSubmitting(true)
2932
agent.Activities.create(activity).then(() => {
3033
setActivities([...activities, activity])
3134
setSelectedActivity(activity)
3235
setEditMode(false)
3336
})
37+
.then(() => setSubmitting(false))
3438
}
3539

3640
const handleEditActivity = (activity: IActivity) => {
41+
setSubmitting(true)
3742
agent.Activities.update(activity).then(() => {
3843
setActivities([...activities.filter(item => item.id !== activity.id), activity])
3944
setSelectedActivity(activity)
4045
setEditMode(false)
4146
})
47+
.then(() => setSubmitting(false))
4248
}
4349

44-
const handleDeleteActivity = (id: string) => {
50+
const handleDeleteActivity = (event: SyntheticEvent<HTMLButtonElement>, id: string) => {
51+
setSubmitting(true)
52+
setTarget(event.currentTarget.name)
4553
agent.Activities.delete(id).then(() => {
4654
setActivities([...activities.filter(activity => activity.id !== id)])
4755
})
56+
.then(() => setSubmitting(false))
4857
}
4958

5059
useEffect(() => {
@@ -62,7 +71,7 @@ const App = () => {
6271
.then(() => setLoading(false))
6372
}, [])
6473

65-
if(loading) return <LoadingComponent content="Loading Activities..."/>
74+
if (loading) return <LoadingComponent content="Loading Activities..." />
6675

6776
return (
6877
<Fragment>
@@ -78,6 +87,8 @@ const App = () => {
7887
createActivity={handleCreateActivity}
7988
editActivity={handleEditActivity}
8089
deleteActivity={handleDeleteActivity}
90+
submitting={submitting}
91+
target={target}
8192
/>
8293
</Container>
8394
</Fragment>

src/features/activities/dashboard/ActivityDashboard.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react'
1+
import React, { SyntheticEvent } from 'react'
22
import { Grid } from 'semantic-ui-react'
33

44
import { IActivity } from '../../../app/models/activity'
@@ -15,7 +15,9 @@ interface IProps {
1515
setSelectedActivity: (activity: IActivity | null) => void
1616
createActivity: (activity: IActivity) => void
1717
editActivity: (activity: IActivity) => void
18-
deleteActivity: (id: string) => void
18+
deleteActivity: (event: SyntheticEvent<HTMLButtonElement>,id: string) => void
19+
submitting: boolean,
20+
target: string
1921
}
2022

2123
const ActivityDashboard: React.FC<IProps> = ({
@@ -27,14 +29,18 @@ const ActivityDashboard: React.FC<IProps> = ({
2729
setSelectedActivity,
2830
createActivity,
2931
editActivity,
30-
deleteActivity
32+
deleteActivity,
33+
submitting,
34+
target
3135
}) => (
3236
<Grid>
3337
<Grid.Column width={10}>
3438
<ActivityList
3539
activities={activities}
3640
selectActivity={selectActivity}
3741
deleteActivity={deleteActivity}
42+
submitting={submitting}
43+
target={target}
3844
/>
3945
</Grid.Column>
4046
<Grid.Column width={6}>
@@ -56,6 +62,7 @@ const ActivityDashboard: React.FC<IProps> = ({
5662
activity={selectedActivity}
5763
createActivity={createActivity}
5864
editActivity={editActivity}
65+
submitting={submitting}
5966
/>
6067
)}
6168
</Grid.Column>

src/features/activities/dashboard/ActivityList.tsx

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
1-
import React from 'react'
1+
import React, { SyntheticEvent } from 'react'
22
import { Item, Button, Label, Segment } from 'semantic-ui-react'
33

44
import { IActivity } from '../../../app/models/activity'
55

66
interface IProps {
77
activities: IActivity[]
88
selectActivity: (id: string) => void
9-
deleteActivity: (id: string) => void
9+
deleteActivity: (event: SyntheticEvent<HTMLButtonElement>,id: string) => void
10+
submitting: boolean
11+
target: string
1012
}
1113

12-
const ActivityList: React.FC<IProps> = ({ activities, selectActivity, deleteActivity }) => (
14+
const ActivityList: React.FC<IProps> = ({
15+
activities,
16+
selectActivity,
17+
deleteActivity,
18+
submitting,
19+
target
20+
}) => (
1321
<Segment clearing>
1422
<Item.Group divided>
1523
{
@@ -30,7 +38,9 @@ const ActivityList: React.FC<IProps> = ({ activities, selectActivity, deleteActi
3038
color='blue'
3139
/>
3240
<Button
33-
onClick={() => deleteActivity(activity.id)}
41+
name={activity.id}
42+
loading={target === activity.id && submitting}
43+
onClick={(e) => deleteActivity(e, activity.id)}
3444
floated='right'
3545
content='Delete'
3646
color='red'

src/features/activities/form/ActivityForm.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ interface IProps {
88
activity: IActivity | null,
99
createActivity: (activity: IActivity) => void
1010
editActivity: (activity: IActivity) => void
11+
submitting: boolean
1112
}
1213

1314
const ActivityForm: React.FC<IProps> = ({
1415
setEditMode,
1516
activity: initialFormState,
1617
createActivity,
17-
editActivity
18+
editActivity,
19+
submitting
1820
}) => {
1921
const initializeForm = () => {
2022
if (initialFormState) {
@@ -91,7 +93,7 @@ const ActivityForm: React.FC<IProps> = ({
9193
name='venue'
9294
placeholder='Venue'
9395
value={activity.venue} />
94-
<Button floated='right' positive type='submit' content='Submit' />
96+
<Button loading={submitting} floated='right' positive type='submit' content='Submit' />
9597
<Button onClick={() => setEditMode(false)} floated='right' type='button' content='Cancel' />
9698
</Form>
9799
</Segment>

src/tests/components/ActivityDashboard.test.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ test('Should render ActivityDashboard correctly with editMode equals to false',
1616
createActivity={() => { }}
1717
editActivity={() => { }}
1818
deleteActivity={() => { }}
19+
submitting={false}
20+
target=''
1921
/>
2022
)
2123

@@ -34,6 +36,8 @@ test('Should render ActivityDashboard correctly with editMode equals to true', (
3436
createActivity={() => { }}
3537
editActivity={() => { }}
3638
deleteActivity={() => { }}
39+
submitting={false}
40+
target=''
3741
/>
3842
)
3943

@@ -52,6 +56,8 @@ test('Should render ActivityDashboard correctly with edit mode false and selecte
5256
createActivity={() => { }}
5357
editActivity={() => { }}
5458
deleteActivity={() => { }}
59+
submitting={false}
60+
target=''
5561
/>
5662
)
5763

src/tests/components/ActivityForm.test.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ test('Should render ActivityForm correctly when activity prop is null', () => {
1212
activity={null}
1313
createActivity={() => { }}
1414
editActivity={() => { }}
15+
submitting={false}
1516
/>
1617
)
1718

@@ -25,6 +26,7 @@ test('Should render ActivityForm correctly with given activity', () => {
2526
activity={fakeActivities[0]}
2627
createActivity={() => { }}
2728
editActivity={() => { }}
29+
submitting={false}
2830
/>
2931
)
3032

@@ -40,6 +42,7 @@ test('Should call setEditMode with false when Cancel button is clicked ', () =>
4042
activity={fakeActivities[0]}
4143
createActivity={() => { }}
4244
editActivity={() => { }}
45+
submitting={false}
4346
/>
4447
)
4548

src/tests/components/ActivityList.test.tsx

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ test('Should render ActivityList correctly', () => {
1010
activities={fakeActivities}
1111
selectActivity={() => { }}
1212
deleteActivity={() => { }}
13-
/>)
13+
submitting={false}
14+
target=''
15+
/>
16+
)
1417

1518
expect(wrapper).toMatchSnapshot()
1619
})
@@ -23,7 +26,11 @@ test('Should call selectActivity once when button is clicked', () => {
2326
activities={fakeActivities}
2427
selectActivity={selectActivitySpy}
2528
deleteActivity={() => { }}
26-
/>)
29+
submitting={false}
30+
target=''
31+
/>
32+
)
33+
2734
wrapper.find('Button').first().simulate('click')
2835
expect(selectActivitySpy).toHaveBeenCalledTimes(1)
2936
})
@@ -35,8 +42,11 @@ test('Should call deleteActivity once when delete button is clicked', () => {
3542
activities={fakeActivities}
3643
selectActivity={() => { }}
3744
deleteActivity={deleteActivitySpy}
38-
/>)
45+
submitting={false}
46+
target=''
47+
/>
48+
)
3949

40-
wrapper.find('Button').at(1).simulate('click')
41-
expect(deleteActivitySpy).toHaveBeenCalledTimes(1)
50+
wrapper.find('Button').at(1).simulate('click')
51+
expect(deleteActivitySpy).toHaveBeenCalledTimes(1)
4252
})

src/tests/components/__snapshots__/ActivityDashboard.test.tsx.snap

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ exports[`Should render ActivityDashboard correctly with edit mode false and sele
3030
}
3131
deleteActivity={[Function]}
3232
selectActivity={[Function]}
33+
submitting={false}
34+
target=""
3335
/>
3436
</GridColumn>
3537
<GridColumn
@@ -68,6 +70,8 @@ exports[`Should render ActivityDashboard correctly with editMode equals to false
6870
}
6971
deleteActivity={[Function]}
7072
selectActivity={[Function]}
73+
submitting={false}
74+
target=""
7175
/>
7276
</GridColumn>
7377
<GridColumn
@@ -122,6 +126,8 @@ exports[`Should render ActivityDashboard correctly with editMode equals to true
122126
}
123127
deleteActivity={[Function]}
124128
selectActivity={[Function]}
129+
submitting={false}
130+
target=""
125131
/>
126132
</GridColumn>
127133
<GridColumn
@@ -143,6 +149,7 @@ exports[`Should render ActivityDashboard correctly with editMode equals to true
143149
editActivity={[Function]}
144150
key="1"
145151
setEditMode={[Function]}
152+
submitting={false}
146153
/>
147154
</GridColumn>
148155
</Grid>

src/tests/components/__snapshots__/ActivityForm.test.tsx.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ exports[`Should render ActivityForm correctly when activity prop is null 1`] = `
6262
as="button"
6363
content="Submit"
6464
floated="right"
65+
loading={false}
6566
positive={true}
6667
type="submit"
6768
/>
@@ -138,6 +139,7 @@ exports[`Should render ActivityForm correctly with given activity 1`] = `
138139
as="button"
139140
content="Submit"
140141
floated="right"
142+
loading={false}
141143
positive={true}
142144
type="submit"
143145
/>

src/tests/components/__snapshots__/ActivityList.test.tsx.snap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ exports[`Should render ActivityList correctly 1`] = `
4242
color="red"
4343
content="Delete"
4444
floated="right"
45+
loading={false}
46+
name="1"
4547
onClick={[Function]}
4648
/>
4749
<Label
@@ -86,6 +88,8 @@ exports[`Should render ActivityList correctly 1`] = `
8688
color="red"
8789
content="Delete"
8890
floated="right"
91+
loading={false}
92+
name="2"
8993
onClick={[Function]}
9094
/>
9195
<Label

0 commit comments

Comments
 (0)