Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Generic ListEditor #656

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions graphql/fragments/findAnimeFields.fragment.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,9 @@ fragment findAnimeFields on Anime {
nextRelease
status
tba
characters(first: 1) {
nodes {
...findMediaCharacterFields
}
}
}
7 changes: 7 additions & 0 deletions graphql/fragments/findMediaCharacterFields.fragment.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
fragment findMediaCharacterFields on MediaCharacter {
id
role
character {
id
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
"husky": "^4.3.0",
"lint-staged": "^10.5.1",
"prettier": "^2.2.0",
"typescript": "^4.1.3"
"typescript": "4.4.0-beta"
},
"scripts": {
"start": "react-scripts start",
Expand Down
140 changes: 15 additions & 125 deletions src/components/anime/AnimeEdit.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,24 @@
import React, { ReactElement, useEffect, useReducer, useState } from 'react';
import {
AgeRatingEnum,
FindAnimeFieldsFragment,
ReleaseStatusEnum,
useUpdateDraftMutationMutation,
useSubmitDraftMutationMutation,
WikiSubmissionFieldsFragment,
} from 'src/types/graphql';
import { ReactElement, useEffect } from 'react';
import Sidebar from '../ui/navigation';
import SingleSelectInput from '../ui/input/SingleSelectInput';
import EditGroup from '../media/EditGroup';
import {
TextInput,
TitlesInput,
DateInput,
DateTimeInput,
TextAreaInput,
} from 'src/components/ui/input';
import animeReducer from './animeReducer';

interface AnimeInterface {
record: FindAnimeFieldsFragment;
wikiSubmission: WikiSubmissionFieldsFragment;
}

export default function AnimeEdit({ record, wikiSubmission }: AnimeInterface): ReactElement {
const [original] = useState(record);
const [update, dispatch] = useReducer(animeReducer, wikiSubmission.data);
import { AnimeChangeEditInterface } from 'src/types/editTypes';
import AnimeItem from './AnimeItem';
import { useSubmitDraftMutationMutation, useUpdateDraftMutationMutation } from 'src/types/graphql';

export default function AnimeEdit({
record,
wikiSubmission,
cache,
dispatch,
}: AnimeChangeEditInterface): ReactElement {
const inputVariables = {
variables: {
input: {
id: wikiSubmission.id,
data: update,
data: cache,
},
},
};

const [updateDraftMutation, { data, loading, error }] = useUpdateDraftMutationMutation(
inputVariables
);
Expand All @@ -45,113 +29,19 @@ export default function AnimeEdit({ record, wikiSubmission }: AnimeInterface): R

useEffect(() => {
updateDraftMutation();
}, [update, updateDraftMutation]);
}, [cache, updateDraftMutation]);

const handleSubmit = (e: any) => {
e.preventDefault();

submitDraftMutation();
console.log(update);
};

return (
<>
<Sidebar />
<form onSubmit={handleSubmit}>
<EditGroup title='Mods Only'>
<>
{/* figure out how to make parentDispatch optional when readOnly is supplied */}
<TextInput
readOnly
fieldType='id'
initialValue={original.id}
parentDispatch={dispatch}
/>
<TextInput
fieldType='slug'
cache={update.slug}
initialValue={original.slug}
parentDispatch={dispatch}
/>
</>
</EditGroup>

<EditGroup title='Titles'>
<>
<TitlesInput
key='titles'
cache={update.titles}
titles={original.titles}
dispatch={dispatch}
/>
</>
</EditGroup>

<EditGroup title='Synopsis and Age Rating'>
<>
<TextAreaInput
fieldType='description.en'
label='Description'
cache={update.description}
initialValue={original.description.en}
parentDispatch={dispatch}
/>

<SingleSelectInput<AgeRatingEnum>
fieldType='ageRating'
initialValue={original.ageRating}
options={Object.values(AgeRatingEnum)}
parentDispatch={dispatch}
/>

<TextInput
fieldType='ageRatingGuide'
cache={update.ageRatingGuide}
initialValue={original.ageRatingGuide}
parentDispatch={dispatch}
/>
</>
</EditGroup>

<DateInput
fieldType='startDate'
cache={update.startDate}
initialValue={original.startDate}
parentDispatch={dispatch}
/>

<DateInput
fieldType='endDate'
cache={update.endDate}
initialValue={original.endDate}
parentDispatch={dispatch}
/>

<DateTimeInput
fieldType='nextRelease'
cache={update.nextRelease}
initialValue={original.nextRelease}
parentDispatch={dispatch}
/>

<EditGroup title='Release'>
<>
<SingleSelectInput<ReleaseStatusEnum>
fieldType='release'
cache={update.status}
initialValue={original.status}
options={Object.values(ReleaseStatusEnum)}
parentDispatch={dispatch}
/>

<TextInput
fieldType='tba'
cache={update.tba}
initialValue={original.tba}
parentDispatch={dispatch}
/>
</>
</EditGroup>
<AnimeItem record={record} cache={cache} parentDispatch={dispatch} />

<input type='submit' value='Submit' />
</form>
Expand Down
129 changes: 129 additions & 0 deletions src/components/anime/AnimeItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import { ReactElement, useState } from 'react';
import { AgeRatingEnum, ReleaseStatusEnum } from 'src/types/graphql';
import { AnimeItemInterface, MediaCharacterItemInterface } from 'src/types/itemTypes';
import EditGroup from '../media/EditGroup';
import MediaCharacterItem from '../mediaCharacter/MediaCharacterEdit';
import {
DateInput,
DateTimeInput,
SingleSelectInput,
TextAreaInput,
TextInput,
TitlesInput,
} from '../ui/input';
import ListEditor from '../ui/ListEditor';

export default function AnimeItem({
record,
cache,
parentDispatch,
}: AnimeItemInterface): ReactElement {
const [original] = useState(record);

return (
<>
<EditGroup title='Mods Only'>
<>
{/* figure out how to make parentDispatch optional when readOnly is supplied */}
<TextInput
readOnly
fieldType='id'
initialValue={original.id}
parentDispatch={parentDispatch}
/>
<TextInput
fieldType='slug'
cache={cache.slug}
initialValue={original.slug}
parentDispatch={parentDispatch}
/>
</>
</EditGroup>

<EditGroup title='Titles'>
<>
<TitlesInput
key='titles'
cache={cache.titles}
titles={original.titles}
parentDispatch={parentDispatch}
/>
</>
</EditGroup>

<EditGroup title='Synopsis and Age Rating'>
<>
<TextAreaInput
fieldType='description.en'
label='Description'
cache={cache.description}
initialValue={original.description.en}
parentDispatch={parentDispatch}
/>

{/* NOTE: there is some bug with lists here when changing will cause error. */}
<SingleSelectInput<AgeRatingEnum>
fieldType='ageRating'
initialValue={original.ageRating}
options={Object.values(AgeRatingEnum)}
parentDispatch={parentDispatch}
/>

<TextInput
fieldType='ageRatingGuide'
cache={cache.ageRatingGuide}
initialValue={original.ageRatingGuide}
parentDispatch={parentDispatch}
/>
</>
</EditGroup>

<DateInput
fieldType='startDate'
cache={cache.startDate}
initialValue={original.startDate}
parentDispatch={parentDispatch}
/>

<DateInput
fieldType='endDate'
cache={cache.endDate}
initialValue={original.endDate}
parentDispatch={parentDispatch}
/>

<DateTimeInput
fieldType='nextRelease'
cache={cache.nextRelease}
initialValue={original.nextRelease}
parentDispatch={parentDispatch}
/>

<EditGroup title='Release'>
<>
<SingleSelectInput<ReleaseStatusEnum>
fieldType='release'
cache={cache.status}
initialValue={original.status}
options={Object.values(ReleaseStatusEnum)}
parentDispatch={parentDispatch}
/>

<TextInput
fieldType='tba'
cache={cache.tba}
initialValue={original.tba}
parentDispatch={parentDispatch}
/>
</>
</EditGroup>

<ListEditor<MediaCharacterItemInterface>
Component={MediaCharacterItem}
initialItems={original.characters.nodes}
cache={cache.mediaCharacters}
parentDispatch={parentDispatch}
/>
</>
);
}
19 changes: 2 additions & 17 deletions src/components/anime/animeReducer.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,9 @@
import { MediaChange } from 'src/types/mediaChange';
import { ReducerAction } from 'src/types/reducer';
import animeState from 'src/util/reducerState/animeState';
import localizedState from 'src/util/reducerState/localizedState';
import titleState from 'src/util/reducerState/titleState';

export default function animeReducer(state: MediaChange, action: ReducerAction): MediaChange {
const splitActions = action.type.split('.');

switch (splitActions[0]) {
case 'titles': {
const fieldName = splitActions.slice(-1)[0];
return titleState<MediaChange>(state, fieldName, action.payload, action.action);
}
case 'description': {
const [fieldName, language] = splitActions;
return localizedState<MediaChange>(state, fieldName, language, action.payload);
}
default:
return {
...state,
[action.type]: action.payload.value,
};
}
return animeState(state, action);
}
23 changes: 23 additions & 0 deletions src/components/mediaCharacter/MediaCharacterEdit.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ReactElement } from 'react';
import { CharacterRoleEnum } from 'src/types/graphql';
import { MediaCharacterItemInterface } from 'src/types/itemTypes';
import { SingleSelectInput, TextInput } from '../ui/input';

export default function MediaCharacterItem({
record,
cache,
parentDispatch,
}: MediaCharacterItemInterface): ReactElement {
return (
<>
<TextInput readOnly fieldType='id' initialValue={record.id} parentDispatch={parentDispatch} />
<SingleSelectInput<CharacterRoleEnum>
fieldType='role'
initialValue={record.role}
options={Object.values(CharacterRoleEnum)}
cache={cache.role}
parentDispatch={parentDispatch}
/>
</>
);
}
Loading