-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9c33a59
commit ede2695
Showing
9 changed files
with
817 additions
and
199 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,77 +1,71 @@ | ||
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; | ||
import axios from 'axios'; | ||
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'; | ||
|
||
const apiUrl = 'https://api.spacexdata.com/v3/missions'; | ||
export const fetchMissions = createAsyncThunk( | ||
'missions/fetchMissions', | ||
async () => { | ||
const response = await fetch('https://api.spacexdata.com/v3/missions'); | ||
const data = await response.json(); | ||
const result = []; | ||
data.forEach((mission) => { | ||
result.push({ | ||
name: mission.mission_name, | ||
description: mission.description, | ||
id: mission.mission_id, | ||
reserved: false, | ||
}); | ||
}); | ||
return result; | ||
}, | ||
); | ||
|
||
const initialState = { | ||
missions: [], | ||
reserved: false, | ||
isLoading: false, | ||
pending: false, | ||
error: false, | ||
}; | ||
|
||
export const getMissions = createAsyncThunk('missions/getMissions', async (thunkAPI) => { | ||
try { | ||
const userData = localStorage.getItem('Missions'); | ||
|
||
if (userData === null) { | ||
const resp = await axios.get(apiUrl); | ||
const transformedmissions = Object.keys(resp.data).map((key) => { | ||
const MissionData = resp.data[key]; | ||
return { | ||
mission_id: key, | ||
mission_name: MissionData.mission_name, | ||
description: MissionData.description, | ||
reserved: false, | ||
}; | ||
}); | ||
|
||
return transformedmissions; | ||
} | ||
return JSON.parse(userData); | ||
} catch (error) { | ||
return thunkAPI.rejectWithValue(error); | ||
} | ||
}); | ||
|
||
const MissionSlice = createSlice({ | ||
const missionsSlice = createSlice({ | ||
name: 'missions', | ||
initialState, | ||
reducers: { | ||
reserveMission: (state, { payload }) => { | ||
const updatedMissions = state.missions.map((mission) => { | ||
if (mission.mission_id === payload.missionId) { | ||
return { | ||
handleMission: (state, { payload }) => { | ||
const missions = []; | ||
state.missions.forEach((mission) => { | ||
if (mission.id === payload) { | ||
missions.push({ | ||
...mission, | ||
reserved: !mission.reserved, | ||
}; | ||
}); | ||
} else { | ||
missions.push({ ...mission }); | ||
} | ||
return mission; | ||
}); | ||
|
||
// Update local storage with the updated missions | ||
localStorage.setItem('Missions', JSON.stringify(updatedMissions)); | ||
|
||
return { | ||
...state, | ||
missions: updatedMissions, // Update the missions array | ||
missions, | ||
}; | ||
}, | ||
}, | ||
extraReducers(builder) { | ||
builder | ||
.addCase(getMissions.pending, (state) => { | ||
state.isLoading = true; | ||
}) | ||
.addCase(getMissions.fulfilled, (state, action) => { | ||
state.isLoading = false; | ||
state.missions = action.payload; | ||
}) | ||
.addCase(getMissions.rejected, (state, action) => { | ||
state.isLoading = false; | ||
state.error = action.payload; | ||
}); | ||
extraReducers: (builder) => { | ||
builder.addCase(fetchMissions.fulfilled, (state, { payload }) => ({ | ||
...state, | ||
missions: payload, | ||
pending: false, | ||
error: false, | ||
})); | ||
builder.addCase(fetchMissions.pending, (state) => ({ | ||
...state, | ||
pending: true, | ||
error: false, | ||
})); | ||
|
||
builder.addCase(fetchMissions.rejected, (state) => ({ | ||
...state, | ||
pending: false, | ||
error: true, | ||
})); | ||
}, | ||
}); | ||
|
||
export default MissionSlice.reducer; | ||
export const { reserveMission } = MissionSlice.actions; | ||
export default missionsSlice.reducer; | ||
export const { handleMission } = missionsSlice.actions; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,50 +1,48 @@ | ||
// import PropTypes from 'prop-types'; | ||
// import { useDispatch } from 'react-redux'; | ||
// import { handleMission } from '../Redux/Missions/MissionSlice'; | ||
import PropTypes from 'prop-types'; | ||
import { useDispatch } from 'react-redux'; | ||
import { handleMission } from '../Redux/Missions/MissionSlice'; | ||
|
||
// const MissionCard = ({ props }) => { | ||
// const { | ||
// name, description, reserved, id, | ||
// } = props; | ||
// const dispatch = useDispatch(); | ||
// const getButton = (reserved, btn) => { | ||
// let button; | ||
// if (btn === 'member') { | ||
// button = reserved ? ( | ||
// <span className="active-member-badge">active member</span> | ||
// ) : ( | ||
// <span className="not-member-badge">Not a member</span> | ||
// ); | ||
// } | ||
// if (btn === 'mission') { | ||
// button = reserved ? ( | ||
// <button className="leave-mission-btn" type="button" onClick={() => | ||
// dispatch(handleMission(id))}> | ||
// Leave Mission | ||
// </button> | ||
// ) : ( | ||
// <button className="join-mission-btn" type="button" onClick={() => | ||
// dispatch(handleMission(id))}> | ||
// Join Mission</button> | ||
// ); | ||
// } | ||
// return button; | ||
// }; | ||
// return ( | ||
// <> | ||
// <td className="mission-name">{name}</td> | ||
// <td className="mission-description">{description}</td> | ||
// <td className="table-badges">{getButton(reserved, 'member')}</td> | ||
// <td className="table-btns">{getButton(reserved, 'mission')}</td> | ||
// </> | ||
// ); | ||
// }; | ||
// MissionCard.propTypes = { | ||
// props: PropTypes.shape({ | ||
// }).isRequired, | ||
// name: PropTypes.string.isRequired, | ||
// description: PropTypes.string.isRequired, | ||
// reserved: PropTypes.bool.isRequired, | ||
// id: PropTypes.string.isRequired, | ||
// }; | ||
// export default MissionCard; | ||
const MissionCard = ({ props }) => { | ||
const { | ||
name, description, reserved, id, | ||
} = props; | ||
const dispatch = useDispatch(); | ||
|
||
const getButton = (reserved, btn) => { | ||
let button; | ||
if (btn === 'member') { | ||
button = reserved ? ( | ||
<span className="active-member-badge">active member</span> | ||
) : ( | ||
<span className="not-member-badge">Not a member</span> | ||
); | ||
} | ||
if (btn === 'mission') { | ||
button = reserved ? ( | ||
<button className="leave-mission-btn" type="button" onClick={() => dispatch(handleMission(id))}>Leave Mission</button> | ||
) : ( | ||
<button className="join-mission-btn" type="button" onClick={() => dispatch(handleMission(id))}>Join Mission</button> | ||
); | ||
} | ||
return button; | ||
}; | ||
|
||
return ( | ||
<> | ||
<td className="mission-name">{name}</td> | ||
<td className="mission-description">{description}</td> | ||
<td className="table-badges">{getButton(reserved, 'member')}</td> | ||
<td className="table-btns">{getButton(reserved, 'mission')}</td> | ||
</> | ||
); | ||
}; | ||
|
||
MissionCard.propTypes = { | ||
props: PropTypes.shape({ | ||
}).isRequired, | ||
name: PropTypes.string.isRequired, | ||
description: PropTypes.string.isRequired, | ||
reserved: PropTypes.bool.isRequired, | ||
id: PropTypes.string.isRequired, | ||
}; | ||
export default MissionCard; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,72 +1,55 @@ | ||
import { useEffect } from 'react'; | ||
import { useDispatch, useSelector } from 'react-redux'; | ||
// import { fetchMissions } from '../Redux/Missions/MissionSlice'; | ||
import { fetchMissions } from '../Redux/Missions/MissionSlice'; | ||
import '../styles/css/Missions.css'; | ||
import { getMissions, reserveMission } from '../Redux/Missions/MissionSlice'; | ||
import MissionCard from './MissionCard'; | ||
|
||
const Missions = () => { | ||
const { isLoading, missions } = useSelector((state) => state.missions); | ||
const dispatch = useDispatch(); | ||
|
||
const { missions, pending, error } = useSelector((store) => store.missions); | ||
useEffect(() => { | ||
dispatch(getMissions()); | ||
}, [dispatch]); | ||
|
||
// Function to handle joining/leaving a mission | ||
const handleMissionAction = (mission) => { | ||
// Update the reserved flag in the Redux state | ||
dispatch(reserveMission({ missionId: mission.mission_id })); | ||
}; | ||
if (missions.length < 1) { | ||
dispatch(fetchMissions()); | ||
} | ||
}, [dispatch, missions.length]); | ||
|
||
if (isLoading) { | ||
return ( | ||
<div> | ||
<h1>Loading...</h1> | ||
</div> | ||
); | ||
} | ||
let content; | ||
|
||
return ( | ||
<div className="MissionsComponent"> | ||
if (!pending && !error && Array.isArray(missions)) { | ||
content = ( | ||
<table className="missions-table"> | ||
<thead> | ||
<tr> | ||
<tbody> | ||
<tr key="missions"> | ||
<th>Mission</th> | ||
<th>Description</th> | ||
<th>Status</th> | ||
<th>Action</th> | ||
<th>{' '}</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
{missions.length > 0 ? ( | ||
missions.map((mission) => ( | ||
<tr key={mission.mission_id}> | ||
<td>{mission.mission_name}</td> | ||
<td className="description">{mission.description}</td> | ||
<td> | ||
<p className="status">{mission.reserved ? 'Active Member' : 'NOT A MEMBER'}</p> | ||
</td> | ||
<td> | ||
<button | ||
type="button" | ||
className={`joinBtn ${mission.reserved ? 'clicked' : ''}`} | ||
onClick={() => { | ||
handleMissionAction(mission); | ||
}} | ||
> | ||
{mission.reserved ? 'Leave Mission' : 'Join Mission'} | ||
</button> | ||
</td> | ||
</tr> | ||
)) | ||
) : ( | ||
<tr> | ||
<td colSpan="4">No Missions available</td> | ||
{missions.map((mission) => ( | ||
<tr key={mission.id}> | ||
<MissionCard props={mission} /> | ||
</tr> | ||
)} | ||
))} | ||
</tbody> | ||
</table> | ||
</div> | ||
); | ||
} | ||
|
||
if (pending) { | ||
content = ( | ||
<h1>Fetching Missions</h1> | ||
); | ||
} | ||
if (error) { | ||
content = ( | ||
<h1>Error occured while fetching missions</h1> | ||
); | ||
} | ||
return ( | ||
<section className="missions"> | ||
{content} | ||
</section> | ||
); | ||
}; | ||
|
||
export default Missions; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.