Skip to content

Commit

Permalink
Add mission test files
Browse files Browse the repository at this point in the history
  • Loading branch information
fatmahussein committed Sep 7, 2023
1 parent 9c33a59 commit ede2695
Show file tree
Hide file tree
Showing 9 changed files with 817 additions and 199 deletions.
106 changes: 50 additions & 56 deletions src/Redux/Missions/MissionSlice.js
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;
96 changes: 47 additions & 49 deletions src/components/MissionCard.js
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;
87 changes: 35 additions & 52 deletions src/components/Missions.js
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;
32 changes: 21 additions & 11 deletions src/components/MyProfile.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,36 @@
import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { getMissions } from '../Redux/Missions/MissionSlice';
import { handleMission } from '../Redux/Missions/MissionSlice';
import '../css/myProfile.css';

const MyProfile = () => {
const missions = useSelector((state) => state.missions.missions); // Use "missions" directly
const reservedMissions = missions.filter((mission) => mission.reserved === true);
const { missions } = useSelector(((state) => state.missions));
const reserved = missions.filter((mission) => mission.reserved === true);

const dispatch = useDispatch();
useEffect(() => {
dispatch(getMissions());
dispatch(handleMission());
}, [dispatch]);
const { rockets } = useSelector((state) => state.rockets);
const reservedRockets = rockets.filter((rocket) => rocket.reserved === true);
const { dragons } = useSelector((state) => state.dragons);
const reservedDragons = dragons.filter((dragon) => dragon.reserved === true);
let rocketList;
let dragonList;

let missionList;
if (reserved.length > 0) {
missionList = (
<ul className="missions-list">
{reserved.map((mission) => (
<li key={mission.id}>{mission.name}</li>
))}
</ul>
);
} else {
missionList = (
<p className="empty-profile-msg">You have not joined any missions yet</p>
);
}
if (reservedRockets.length > 0) {
rocketList = (
<ul className="rockets-list">
Expand All @@ -42,12 +56,8 @@ const MyProfile = () => {
return (
<div className="my-profile">
<div className="my-missions">
<h2 className="myprofile-header">My Missions</h2>
<ul className="myprofile-list">
{reservedMissions.map((Mission) => (
<li key={Mission.id}>{Mission.mission_name}</li>
))}
</ul>
<p className="missions-headline">My Missions</p>
{missionList}
</div>
<div className="my-rockets">
<p className="rockets-headline">My Rockets</p>
Expand Down
Loading

0 comments on commit ede2695

Please sign in to comment.