Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
SRCT
schedules
Commits
f55ae767
Commit
f55ae767
authored
Jun 16, 2018
by
David Haynes
🙆
Browse files
Finished Massive Refactor
- renaming and sticking with idiomatic react/redux
parent
ea240443
Changes
17
Hide whitespace changes
Inline
Side-by-side
schedules_web/src/actions/schedule/schedule.action-types.ts
View file @
f55ae767
export
const
ADD_
SECTION
:
string
=
'
[Schedule] ADD_
SECTION
'
;
export
const
REMOVE_
SECTION
:
string
=
'
[Schedule] REMOVE_
SECTION
'
;
export
const
ADD_
ENTRY
:
string
=
'
[Schedule] ADD_
ENTRY
'
;
export
const
REMOVE_
ENTRY
:
string
=
'
[Schedule] REMOVE_
ENTRY
'
;
schedules_web/src/actions/schedule/schedule.actions.ts
View file @
f55ae767
import
{
Section
}
from
'
../../util/
section
'
;
import
{
ADD_
SECTION
,
REMOVE_
SECTION
}
from
'
./schedule.action-types
'
;
import
{
CourseEntry
}
from
'
../../util/
CourseEntry
'
;
import
{
ADD_
ENTRY
,
REMOVE_
ENTRY
}
from
'
./schedule.action-types
'
;
export
interface
ScheduleAction
{
type
:
string
;
// What action is to be performed
section
:
Section
;
// The section that is being added/removed
entry
:
CourseEntry
;
// The section that is being added/removed
}
/**
* Add a section to the Schedule
* @param section The section that is to be added
*/
export
const
add
Section
=
(
section
:
Section
):
ScheduleAction
=>
({
type
:
ADD_
SECTION
,
section
:
section
,
export
const
add
Entry
=
(
entry
:
CourseEntry
):
ScheduleAction
=>
({
type
:
ADD_
ENTRY
,
entry
:
entry
,
});
/**
* Remove a section from the Schedule
* @param section The section that is to be removed
*/
export
const
remove
Section
=
(
section
:
Section
):
ScheduleAction
=>
({
type
:
REMOVE_
SECTION
,
section
:
section
,
export
const
remove
Entry
=
(
entry
:
CourseEntry
):
ScheduleAction
=>
({
type
:
REMOVE_
ENTRY
,
entry
:
entry
,
});
schedules_web/src/actions/search/search.action-types.ts
View file @
f55ae767
export
const
SET_SEARCH_
SECTION
S
:
string
=
'
[Search] SET_SE
CTION
S
'
;
export
const
SET_SEARCH_
RESULT
S
:
string
=
'
[Search] SET_SE
ARCH_RESULT
S
'
;
schedules_web/src/actions/search/search.actions.ts
View file @
f55ae767
import
{
Section
}
from
'
../../util/
section
'
;
import
{
SET_SEARCH_
SECTION
S
}
from
'
./search.action-types
'
;
import
{
CourseEntry
}
from
'
../../util/
CourseEntry
'
;
import
{
SET_SEARCH_
RESULT
S
}
from
'
./search.action-types
'
;
export
interface
SearchAction
{
type
:
string
;
se
ctions
:
Section
[];
se
archResults
:
CourseEntry
[];
}
export
const
search
Section
s
=
(
crn
:
string
)
=>
async
(
dispatch
:
any
)
=>
{
export
const
search
Course
s
=
(
crn
:
string
)
=>
async
(
dispatch
:
any
)
=>
{
const
response
=
await
fetch
(
`http://localhost:3000/api/search?crn=
${
crn
}
`
);
const
object
=
await
response
.
json
();
const
section
:
Section
[]
=
[
const
results
:
CourseEntry
[]
=
[
{
id
:
object
.
id
,
name
:
object
.
name
,
...
...
@@ -25,7 +25,7 @@ export const searchSections = (crn: string) => async (dispatch: any) => {
];
dispatch
({
type
:
SET_SEARCH_
SECTION
S
,
se
ctions
:
section
,
type
:
SET_SEARCH_
RESULT
S
,
se
archResults
:
results
,
});
};
schedules_web/src/components/App.tsx
View file @
f55ae767
import
*
as
React
from
'
react
'
;
import
Schedule
from
'
../containers/Schedule
'
;
import
Search
from
'
../containers/Search
'
;
import
Header
from
'
./Header
'
;
...
...
@@ -6,6 +7,7 @@ const App = () => (
<
div
>
<
Header
/>
<
Search
/>
<
Schedule
/>
</
div
>
);
...
...
schedules_web/src/components/S
ection
List.tsx
→
schedules_web/src/components/S
chedule
List.tsx
View file @
f55ae767
import
*
as
React
from
'
react
'
;
import
{
Section
}
from
'
../util/
section
'
;
import
{
CourseEntry
}
from
'
../util/
CourseEntry
'
;
interface
Props
{
sections
:
Section
[];
buttonText
:
string
;
selectSectionCallback
?:
(
section
:
Section
)
=>
void
;
courses
:
CourseEntry
[];
selectCourseCallback
?:
(
entry
:
CourseEntry
)
=>
void
;
}
export
default
class
S
ection
List
extends
React
.
Component
<
Props
,
any
>
{
export
default
class
S
chedule
List
extends
React
.
Component
<
Props
,
any
>
{
constructor
(
props
:
Props
)
{
super
(
props
);
}
...
...
@@ -18,7 +17,7 @@ export default class SectionList extends React.Component<Props, any> {
<
tbody
>
<
tr
>
<
th
>
Course
</
th
>
<
th
>
Section
Name
</
th
>
<
th
>
course
Name
</
th
>
<
th
>
CRN
</
th
>
<
th
>
Days
</
th
>
<
th
>
Instructor
</
th
>
...
...
@@ -26,37 +25,35 @@ export default class SectionList extends React.Component<Props, any> {
<
th
>
Time
</
th
>
<
th
/>
</
tr
>
{
this
.
renderRowsFor
Section
s
(
this
.
props
.
section
s
)
}
{
this
.
renderRowsFor
Course
s
(
this
.
props
.
course
s
)
}
</
tbody
>
</
table
>
);
}
renderRowsFor
Sections
(
sections
:
Section
[]):
JSX
.
Element
[]
{
return
sections
.
map
(
section
=>
{
renderRowsFor
Courses
(
courses
:
CourseEntry
[]):
JSX
.
Element
[]
{
return
courses
.
map
(
course
=>
{
return
(
<
tr
key
=
{
section
.
id
}
>
<
td
>
{
section
.
name
}
</
td
>
<
td
>
{
section
.
title
}
</
td
>
<
td
>
{
section
.
crn
}
</
td
>
<
td
>
{
section
.
days
}
</
td
>
<
td
>
{
section
.
instructor
}
</
td
>
<
td
>
{
section
.
location
}
</
td
>
<
td
>
{
[
section
.
startTime
,
section
.
endTime
].
join
(
'
-
'
)
}
</
td
>
{
this
.
renderSelect
SectionColumn
(
section
.
crn
)
}
<
tr
key
=
{
course
.
id
}
>
<
td
>
{
course
.
name
}
</
td
>
<
td
>
{
course
.
title
}
</
td
>
<
td
>
{
course
.
crn
}
</
td
>
<
td
>
{
course
.
days
}
</
td
>
<
td
>
{
course
.
instructor
}
</
td
>
<
td
>
{
course
.
location
}
</
td
>
<
td
>
{
[
course
.
startTime
,
course
.
endTime
].
join
(
'
-
'
)
}
</
td
>
{
this
.
renderSelect
CourseColumn
(
course
.
crn
)
}
</
tr
>
);
});
}
renderSelect
Section
Column
(
rowCRN
:
string
):
JSX
.
Element
{
if
(
this
.
props
.
select
Section
Callback
)
{
const
section
WithCRN
=
this
.
get
Section
WithCRN
(
rowCRN
);
renderSelect
Course
Column
(
rowCRN
:
string
):
JSX
.
Element
{
if
(
this
.
props
.
select
Course
Callback
)
{
const
course
WithCRN
=
this
.
get
course
WithCRN
(
rowCRN
);
return
(
<
td
>
<
button
onClick
=
{
()
=>
this
.
props
.
selectSectionCallback
(
sectionWithCRN
)
}
>
{
this
.
props
.
buttonText
}
</
button
>
<
button
onClick
=
{
()
=>
this
.
props
.
selectCourseCallback
(
courseWithCRN
)
}
>
"Add to schedule"
</
button
>
</
td
>
);
}
else
{
...
...
@@ -64,7 +61,7 @@ export default class SectionList extends React.Component<Props, any> {
}
}
get
Section
WithCRN
(
crn
:
string
):
Section
{
return
this
.
props
.
sections
.
find
(
section
=>
section
.
crn
===
crn
);
get
course
WithCRN
(
crn
:
string
):
CourseEntry
{
return
this
.
props
.
courses
.
find
(
course
=>
course
.
crn
===
crn
);
}
}
schedules_web/src/components/ScheduleRoot.tsx
0 → 100644
View file @
f55ae767
import
*
as
React
from
'
react
'
;
import
{
CourseEntry
}
from
'
../util/CourseEntry
'
;
import
ScheduleList
from
'
./ScheduleList
'
;
interface
SearchRootProps
{
schedule
:
CourseEntry
[];
removeEntry
:
(
CourseEntry
:
CourseEntry
)
=>
any
;
}
// const generateSchedule = (schedule: CourseEntry[]): void => {
// const crns = schedule.map(entry => entry.crn);
// postData(ENDPOINTS.generateCalendar, crns)
// .then(response => response.text())
// .then(icalText => downloadCalendar(icalText));
// };
const
ScheduleRoot
=
({
schedule
,
removeEntry
}:
SearchRootProps
)
=>
(
<
div
>
<
ScheduleList
courses
=
{
schedule
}
selectCourseCallback
=
{
removeEntry
}
/>
{
/* <button onClick={generateSchedule}>Generate Schedule</button> */
}
</
div
>
);
export
default
ScheduleRoot
;
schedules_web/src/components/Search.tsx
deleted
100644 → 0
View file @
ea240443
import
*
as
React
from
'
react
'
;
import
SearchBar
from
'
../components/SearchBar
'
;
import
SectionList
from
'
../components/SectionList
'
;
import
{
Section
}
from
'
../util/section
'
;
interface
SearchProps
{
searchedSections
:
Section
[];
searchSections
:
(
crn
:
string
)
=>
any
;
addSection
:
(
section
:
Section
)
=>
any
;
}
const
Search
=
({
searchedSections
,
searchSections
,
addSection
}:
SearchProps
)
=>
(
<
div
>
<
SearchBar
onSearch
=
{
searchSections
}
/>
<
SectionList
sections
=
{
searchedSections
}
buttonText
=
"Add to schedule"
selectSectionCallback
=
{
addSection
}
/>
</
div
>
);
export
default
Search
;
schedules_web/src/components/SearchBar.tsx
View file @
f55ae767
import
*
as
React
from
'
react
'
;
interface
Props
{
onSearch
:
(
searchTerm
:
string
)
=>
void
;
onSearch
:
(
crn
:
string
)
=>
void
;
}
interface
State
{
...
...
schedules_web/src/components/SearchRoot.tsx
0 → 100644
View file @
f55ae767
import
*
as
React
from
'
react
'
;
import
SearchBar
from
'
../components/SearchBar
'
;
import
SectionList
from
'
../components/ScheduleList
'
;
import
{
CourseEntry
}
from
'
../util/CourseEntry
'
;
interface
SearchRootProps
{
searchResults
:
CourseEntry
[];
searchCourses
:
(
crn
:
string
)
=>
void
;
addEntry
:
(
entry
:
CourseEntry
)
=>
void
;
}
const
SearchRoot
=
({
searchResults
,
searchCourses
,
addEntry
}:
SearchRootProps
)
=>
(
<
div
>
<
SearchBar
onSearch
=
{
searchCourses
}
/>
<
SectionList
courses
=
{
searchResults
}
selectCourseCallback
=
{
addEntry
}
/>
</
div
>
);
export
default
SearchRoot
;
schedules_web/src/containers/App.tsx
deleted
100644 → 0
View file @
ea240443
import
*
as
React
from
'
react
'
;
import
{
connect
}
from
'
react-redux
'
;
import
{
removeSection
}
from
'
../actions/schedule/schedule.actions
'
;
import
SectionList
from
'
../components/SectionList
'
;
import
{
State
}
from
'
../reducers
'
;
import
{
Section
}
from
'
../util/section
'
;
import
{
downloadCalendar
,
ENDPOINTS
,
postData
}
from
'
../util/utilities
'
;
interface
AppProps
{
schedule
:
Section
[];
removeSection
:
(
section
:
Section
)
=>
any
;
}
class
App
extends
React
.
Component
<
AppProps
>
{
constructor
(
props
:
AppProps
)
{
super
(
props
);
}
render
()
{
return
(
<
div
>
<
h2
>
Your schedule
</
h2
>
<
SectionList
sections
=
{
this
.
props
.
schedule
}
buttonText
=
"Remove from schedule"
selectSectionCallback
=
{
this
.
props
.
removeSection
}
/>
<
button
onClick
=
{
this
.
generateSchedule
}
>
Generate Schedule
</
button
>
</
div
>
);
}
// TODO: Only view logic should be in the component.
generateSchedule
=
()
=>
{
const
crns
=
this
.
props
.
schedule
.
map
(
section
=>
section
.
crn
);
postData
(
ENDPOINTS
.
generateCalendar
,
crns
)
.
then
(
response
=>
response
.
text
())
.
then
(
icalText
=>
downloadCalendar
(
icalText
));
};
}
/**
* Take the current schedule in the store and map it to the <App /> component.
* @param state The current Redux store state.
*/
const
mapStateToProps
=
(
state
:
State
)
=>
({
schedule
:
state
.
schedule
,
});
/**
* Ensure that the Redux state is passed into the component.
*/
export
default
connect
(
mapStateToProps
,
{
removeSection
}
)(
App
);
schedules_web/src/containers/Schedule.tsx
0 → 100644
View file @
f55ae767
import
{
connect
}
from
'
react-redux
'
;
import
{
addEntry
,
removeEntry
}
from
'
../actions/schedule/schedule.actions
'
;
import
ScheduleRoot
from
'
../components/ScheduleRoot
'
;
import
{
State
}
from
'
../reducers
'
;
const
mapStateToProps
=
(
state
:
State
)
=>
({
schedule
:
state
.
schedule
,
});
export
default
connect
(
mapStateToProps
,
{
addEntry
,
removeEntry
}
)(
ScheduleRoot
);
schedules_web/src/containers/Search.tsx
View file @
f55ae767
import
{
connect
}
from
'
react-redux
'
;
import
{
add
Section
}
from
'
../actions/schedule/schedule.actions
'
;
import
{
search
Section
s
}
from
'
../actions/search/search.actions
'
;
import
Search
from
'
../components/Search
'
;
import
{
add
Entry
}
from
'
../actions/schedule/schedule.actions
'
;
import
{
search
Course
s
}
from
'
../actions/search/search.actions
'
;
import
Search
Root
from
'
../components/Search
Root
'
;
import
{
State
}
from
'
../reducers
'
;
const
mapStateToProps
=
(
state
:
State
)
=>
({
search
edSection
s
:
state
.
search
.
searchedSection
s
,
search
Result
s
:
state
.
search
Result
s
,
});
export
default
connect
(
mapStateToProps
,
{
search
Sections
,
addSection
}
)(
Search
);
{
search
Courses
,
addEntry
}
)(
Search
Root
);
schedules_web/src/reducers/index.ts
View file @
f55ae767
...
...
@@ -8,7 +8,7 @@ import { search, SearchState } from './search.reducer';
export
interface
State
{
schedule
:
ScheduleState
;
search
:
SearchState
;
search
Results
:
SearchState
;
}
/**
...
...
@@ -16,9 +16,7 @@ export interface State {
*/
const
defaultState
:
State
=
{
schedule
:
[],
search
:
{
searchedSections
:
[],
},
searchResults
:
[],
};
/**
...
...
@@ -28,5 +26,5 @@ const defaultState: State = {
*/
export
const
allReducers
=
(
state
:
State
=
defaultState
,
action
:
any
)
=>
({
schedule
:
schedule
(
state
.
schedule
,
action
),
search
:
search
(
state
.
search
,
action
),
search
Results
:
search
(
state
.
search
Results
,
action
),
});
schedules_web/src/reducers/schedule.reducer.ts
View file @
f55ae767
...
...
@@ -4,18 +4,18 @@
* Perform operations on the current state of the "Schedule" list in the store
* and return a new definition of the state.
*/
import
{
ADD_
SECTION
,
REMOVE_
SECTION
}
from
'
../actions/schedule/schedule.action-types
'
;
import
{
ADD_
ENTRY
,
REMOVE_
ENTRY
}
from
'
../actions/schedule/schedule.action-types
'
;
import
{
ScheduleAction
}
from
'
../actions/schedule/schedule.actions
'
;
import
{
Section
}
from
'
../util/
section
'
;
import
{
CourseEntry
}
from
'
../util/
CourseEntry
'
;
export
type
ScheduleState
=
Section
[];
export
type
ScheduleState
=
CourseEntry
[];
export
const
schedule
=
(
state
:
ScheduleState
=
[],
action
:
ScheduleAction
)
=>
{
switch
(
action
.
type
)
{
case
ADD_
SECTION
:
return
state
.
findIndex
(
s
=>
s
.
crn
===
action
.
section
.
crn
)
===
-
1
?
[...
state
,
action
.
section
]
:
state
;
case
REMOVE_
SECTION
:
return
state
.
filter
(
s
=>
s
.
crn
!==
action
.
section
.
crn
);
case
ADD_
ENTRY
:
return
state
.
findIndex
(
s
=>
s
.
crn
===
action
.
entry
.
crn
)
===
-
1
?
[...
state
,
action
.
entry
]
:
state
;
case
REMOVE_
ENTRY
:
return
state
.
filter
(
s
=>
s
.
crn
!==
action
.
entry
.
crn
);
default
:
return
state
;
}
...
...
schedules_web/src/reducers/search.reducer.ts
View file @
f55ae767
...
...
@@ -4,20 +4,16 @@
* Perform operations on the current state of the "search.searchedSections"
* list in the store and return a new definition of the state.
*/
import
{
SET_SEARCH_
SECTION
S
}
from
'
../actions/search/search.action-types
'
;
import
{
SET_SEARCH_
RESULT
S
}
from
'
../actions/search/search.action-types
'
;
import
{
SearchAction
}
from
'
../actions/search/search.actions
'
;
import
{
Section
}
from
'
../util/
section
'
;
import
{
CourseEntry
}
from
'
../util/
CourseEntry
'
;
export
interface
SearchState
{
searchedSections
:
Section
[];
}
export
type
SearchState
=
CourseEntry
[];
export
const
search
=
(
state
:
SearchState
=
{
searchedSections
:
[]
}
,
action
:
SearchAction
)
=>
{
export
const
search
=
(
state
:
SearchState
=
[]
,
action
:
SearchAction
)
:
SearchState
=>
{
switch
(
action
.
type
)
{
case
SET_SEARCH_SECTIONS
:
return
Object
.
assign
({},
state
,
{
searchedSections
:
[...
action
.
sections
],
});
case
SET_SEARCH_RESULTS
:
return
action
.
searchResults
;
default
:
return
state
;
}
...
...
schedules_web/src/util/
section
.ts
→
schedules_web/src/util/
CourseEntry
.ts
View file @
f55ae767
/**
* util/
section
.ts
* util/
CourseEntry
.ts
*
* Common object interface for all "Section"s.
*/
export
interface
Section
{
export
interface
CourseEntry
{
id
:
number
;
name
:
string
;
title
:
string
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment