Skip to content

Commit

Permalink
Merge branch 'master' into 23-summer/decouple-playground-sicp
Browse files Browse the repository at this point in the history
  • Loading branch information
RichDom2185 authored Aug 4, 2023
2 parents 3699a27 + 0225c9d commit 352ed8b
Show file tree
Hide file tree
Showing 32 changed files with 3,063 additions and 262 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"classnames": "^2.3.2",
"flexboxgrid": "^6.3.1",
"flexboxgrid-helpers": "^1.1.3",
"js-slang": "^1.0.27",
"js-slang": "^1.0.29",
"js-yaml": "^4.1.0",
"konva": "^9.2.0",
"lodash": "^4.17.21",
Expand Down
7 changes: 7 additions & 0 deletions src/commons/application/ApplicationTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@ export enum Role {
Admin = 'admin'
}

// Must match https://github.com/source-academy/stories-backend/blob/main/internal/enums/groups/role.go
export enum StoriesRole {
Standard = 'member',
Moderator = 'moderator',
Admin = 'admin'
}

export enum SupportedLanguage {
JAVASCRIPT = 'JavaScript',
SCHEME = 'Scheme',
Expand Down
3 changes: 2 additions & 1 deletion src/commons/controlBar/ControlBarStepLimit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type DispatchProps = {

type StateProps = {
stepLimit?: number;
stepSize: number;
key: string;
};

Expand All @@ -32,7 +33,7 @@ export const ControlBarStepLimit: React.FC<ControlBarStepLimitProps> = props =>
min={500}
max={5000}
value={props.stepLimit}
stepSize={2}
stepSize={props.stepSize}
onBlur={onBlurAutoScale}
onValueChange={props.handleChangeStepLimit}
/>
Expand Down
1 change: 0 additions & 1 deletion src/commons/mocks/ContextMocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ export function mockRuntimeContext(): Context {
],
agenda: null,
stash: null,
envSteps: -1,
envStepsTotal: 0,
breakpointSteps: []
};
Expand Down
17 changes: 15 additions & 2 deletions src/commons/sagas/BackendSaga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ import {
} from './RequestsSaga';
import { safeTakeEvery as takeEvery } from './SafeEffects';

function selectTokens() {
export function selectTokens() {
return select((state: OverallState) => ({
accessToken: state.session.accessToken,
refreshToken: state.session.refreshToken
Expand Down Expand Up @@ -198,6 +198,9 @@ function* BackendSaga(): SagaIterator {
yield put(actions.setCourseRegistration(courseRegistration));
yield put(actions.setCourseConfiguration(courseConfiguration));
yield put(actions.setAssessmentConfigurations(assessmentConfigurations));

yield put(actions.getStoriesUser());
// TODO: Fetch associated stories group ID
}
/**
* NOTE: Navigation logic is now handled in <Login /> component.
Expand All @@ -211,7 +214,7 @@ function* BackendSaga(): SagaIterator {
yield takeEvery(
FETCH_USER_AND_COURSE,
function* (action: ReturnType<typeof actions.fetchUserAndCourse>): any {
const tokens = yield selectTokens();
const tokens: Tokens = yield selectTokens();

const {
user,
Expand Down Expand Up @@ -241,6 +244,9 @@ function* BackendSaga(): SagaIterator {
yield put(actions.setCourseRegistration(courseRegistration));
yield put(actions.setCourseConfiguration(courseConfiguration));
yield put(actions.setAssessmentConfigurations(assessmentConfigurations));

yield put(actions.getStoriesUser());
// TODO: Fetch associated stories group ID
}
}
);
Expand All @@ -250,6 +256,9 @@ function* BackendSaga(): SagaIterator {
const { config }: { config: CourseConfiguration | null } = yield call(getCourseConfig, tokens);
if (config) {
yield put(actions.setCourseConfiguration(config));

yield put(actions.getStoriesUser());
// TODO: Fetch associated stories group ID
}
});

Expand Down Expand Up @@ -708,6 +717,10 @@ function* BackendSaga(): SagaIterator {
yield put(actions.setCourseConfiguration(courseConfiguration));
yield put(actions.setAssessmentConfigurations(assessmentConfigurations));
yield put(actions.setCourseRegistration(courseRegistration));

yield put(actions.getStoriesUser());
// TODO: Fetch associated stories group ID

yield call(showSuccessMessage, `Switched to ${courseConfiguration.courseName}!`, 5000);
}
);
Expand Down
116 changes: 94 additions & 22 deletions src/commons/sagas/StoriesSaga.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,40 @@
import { SagaIterator } from 'redux-saga';
import { call, put, takeEvery, takeLatest } from 'redux-saga/effects';
import { call, put, select, takeLatest } from 'redux-saga/effects';
import { ADD_NEW_STORIES_USERS_TO_COURSE } from 'src/features/academy/AcademyTypes';
import {
deleteStory,
getStories,
getStory
getStoriesUser,
getStory,
postNewStoriesUsers,
postStory,
updateStory
} from 'src/features/stories/storiesComponents/BackendAccess';
import {
CREATE_STORY,
DELETE_STORY,
GET_STORIES_LIST,
GET_STORIES_USER,
SAVE_STORY,
SET_CURRENT_STORY_ID,
StoryData,
StoryListView,
StoryView
} from 'src/features/stories/StoriesTypes';

import { OverallState } from '../application/ApplicationTypes';
import { Tokens } from '../application/types/SessionTypes';
import { actions } from '../utils/ActionsHelper';
import { showWarningMessage } from '../utils/notifications/NotificationsHelper';
import { defaultStoryContent } from '../utils/StoriesHelper';
import { selectTokens } from './BackendSaga';
import { safeTakeEvery as takeEvery } from './SafeEffects';

export function* storiesSaga(): SagaIterator {
yield takeLatest(GET_STORIES_LIST, function* () {
const tokens: Tokens = yield selectTokens();
const allStories: StoryListView[] = yield call(async () => {
const resp = await getStories();
const resp = await getStories(tokens);
return resp ?? [];
});

Expand All @@ -32,43 +46,101 @@ export function* storiesSaga(): SagaIterator {
yield takeEvery(
SET_CURRENT_STORY_ID,
function* (action: ReturnType<typeof actions.setCurrentStoryId>) {
const tokens: Tokens = yield selectTokens();
const storyId = action.payload;
if (storyId) {
const story: StoryView = yield call(getStory, storyId);
const story: StoryView = yield call(getStory, tokens, storyId);
yield put(actions.setCurrentStory(story));
} else {
const defaultStory: StoryData = {
title: '',
content: defaultStoryContent
content: defaultStoryContent,
pinOrder: null
};
yield put(actions.setCurrentStory(defaultStory));
}
}
);

// yield takeEvery(SAVE_STORY, function* (action: ReturnType<typeof actions.saveStory>) {
// const story = action.payload;
// const updatedStory: StoryView | null = yield call(async () => {
// // TODO: Support pin order
// const resp = await updateStory(story.id, story.title, story.content);
// if (!resp) {
// return null;
// }
// return resp.json();
// });

// // TODO: Check correctness
// if (updatedStory) {
// yield put(actions.setCurrentStory(updatedStory));
// }
// });
yield takeEvery(CREATE_STORY, function* (action: ReturnType<typeof actions.createStory>) {
const tokens: Tokens = yield selectTokens();
const story = action.payload;
const userId: number | undefined = yield select((state: OverallState) => state.stories.userId);

if (userId === undefined) {
showWarningMessage('Failed to create story: Invalid user');
return;
}

const createdStory: StoryView | null = yield call(
postStory,
tokens,
userId,
story.title,
story.content,
story.pinOrder
);

// TODO: Check correctness
if (createdStory) {
yield put(actions.setCurrentStoryId(createdStory.id));
}

yield put(actions.getStoriesList());
});

yield takeEvery(SAVE_STORY, function* (action: ReturnType<typeof actions.saveStory>) {
const tokens: Tokens = yield selectTokens();
const { story, id } = action.payload;
const updatedStory: StoryView | null = yield call(
updateStory,
tokens,
id,
story.title,
story.content,
story.pinOrder
);

// TODO: Check correctness
if (updatedStory) {
yield put(actions.setCurrentStory(updatedStory));
}

yield put(actions.getStoriesList());
});

yield takeEvery(DELETE_STORY, function* (action: ReturnType<typeof actions.deleteStory>) {
const tokens: Tokens = yield selectTokens();
const storyId = action.payload;
yield call(deleteStory, storyId);
yield call(deleteStory, tokens, storyId);

yield put(actions.getStoriesList());
});

yield takeEvery(GET_STORIES_USER, function* () {
const tokens: Tokens = yield selectTokens();
const me: {
id: number;
name: string;
} | null = yield call(getStoriesUser, tokens);

if (!me) {
// set state to undefined
}
});

yield takeEvery(
ADD_NEW_STORIES_USERS_TO_COURSE,
function* (action: ReturnType<typeof actions.addNewStoriesUsersToCourse>): any {
const tokens: Tokens = yield selectTokens();
const { users, provider } = action.payload;

yield call(postNewStoriesUsers, tokens, users, provider);

// TODO: Refresh the list of story users
// once that page is implemented
}
);
}

export default storiesSaga;
Loading

0 comments on commit 352ed8b

Please sign in to comment.