Skip to content

Commit

Permalink
feat: 回答の詳細を表示する画面でラベルを設定できるようにする機能を実装
Browse files Browse the repository at this point in the history
  • Loading branch information
rito528 committed Aug 16, 2024
1 parent 428d050 commit aad46f9
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@ import { useForm } from 'react-hook-form';
import { removeDuplicates } from '@/generic/ArrayExtra';
import { formatString } from '@/generic/DateFormatter';
import type {
GetAnswerLabelsResponse,
GetAnswerResponse,
GetQuestionsResponse,
} from '@/app/api/_schemas/ResponseSchemas';
import Autocomplete from '@mui/material/Autocomplete';
import Chip from '@mui/material/Chip';
import Box from '@mui/material/Box';

const AnswerTitleForm = (props: { answers: GetAnswerResponse }) => {
const { handleSubmit, register } = useForm<{ title: string }>();
Expand Down Expand Up @@ -70,7 +74,48 @@ const AnswerTitleForm = (props: { answers: GetAnswerResponse }) => {
);
};

const AnswerMeta = (props: { answers: GetAnswerResponse }) => {
const AnswerTags = (props: { labels: GetAnswerLabelsResponse }) => {
return (
<Autocomplete
multiple
id="label"
options={props.labels.map((label) => label.name)}
getOptionLabel={(option) => option}
defaultValue={[]}
renderTags={(value: readonly string[], getTagProps) =>
value.map((option: string, index: number) => (
<Chip
label={option}
sx={{ background: '#FFFFFF29' }}
{...getTagProps({ index })}
key={index}
/>
))
}
renderOption={(props, option) => {
return (
<Box component="span" {...props} style={{ color: 'black' }}>
{option}
</Box>
);
}}
renderInput={(params) => (
// @ts-expect-error (解決方法がよくわからないのでとりあえずignoreする)
// FIXME: あとで調べる
<TextField
{...params}
variant="standard"
sx={{ borderBottom: '1px solid #FFFFFF6B' }}
/>
)}
/>
);
};

const AnswerMeta = (props: {
answers: GetAnswerResponse;
labels: GetAnswerLabelsResponse;
}) => {
return (
<Grid container spacing={2}>
<Grid item xs={6}>
Expand All @@ -81,6 +126,10 @@ const AnswerMeta = (props: { answers: GetAnswerResponse }) => {
<Typography sx={{ fontWeight: 'bold' }}>回答日時</Typography>
{formatString(props.answers.timestamp)}
</Grid>
<Grid item xs={6}>
<Typography sx={{ fontWeight: 'bold' }}>ラベル</Typography>
<AnswerTags labels={props.labels} />
</Grid>
</Grid>
);
};
Expand All @@ -104,6 +153,7 @@ const Answers = (props: { answers: AnswerWithQuestionInfo }) => {
const AnswerDetails = (props: {
answers: GetAnswerResponse;
questions: GetQuestionsResponse;
labels: GetAnswerLabelsResponse;
}) => {
const answerWithQeustionInfo = removeDuplicates(
props.answers.answers.map((answer) => answer.question_id)
Expand All @@ -123,7 +173,7 @@ const AnswerDetails = (props: {
return (
<Stack spacing={2}>
<AnswerTitleForm answers={props.answers} />
<AnswerMeta answers={props.answers} />
<AnswerMeta answers={props.answers} labels={props.labels} />
{answerWithQeustionInfo.length === 0 ? (
<Typography>回答がありません</Typography>
) : (
Expand Down
12 changes: 10 additions & 2 deletions src/app/(authed)/admin/answer/[answerId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Comments from './_components/Comments';
import adminDashboardTheme from '../../theme/adminDashboardTheme';
import type {
ErrorResponse,
GetAnswerLabelsResponse,
GetAnswerResponse,
GetQuestionsResponse,
} from '@/app/api/_schemas/ResponseSchemas';
Expand All @@ -27,13 +28,19 @@ const Home = ({ params }: { params: { answerId: number } }) => {
: ''
);

if (!answers || !formQuestions) {
const { data: labels, isLoading: isLabelsLoading } = useSWR<
Either<ErrorResponse, GetAnswerLabelsResponse>
>('/api/answers/labels');

if (!answers || !formQuestions || !labels) {
return <LoadingCircular />;
} else if (
(!isAnswersLoading && !answers) ||
(!isFormQuestionsLoading && !formQuestions) ||
(!isLabelsLoading && !labels) ||
answers._tag === 'Left' ||
formQuestions._tag === 'Left'
formQuestions._tag === 'Left' ||
labels._tag === 'Left'
) {
return <ErrorModal />;
}
Expand All @@ -51,6 +58,7 @@ const Home = ({ params }: { params: { answerId: number } }) => {
<AnswerDetails
answers={answers.right}
questions={formQuestions.right}
labels={labels.right}
/>
<Comments
comments={answers.right.comments}
Expand Down
12 changes: 12 additions & 0 deletions src/app/api/_schemas/ResponseSchemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,18 @@ export const getAnswersResponseSchema = z

export type GetAnswersResponse = z.infer<typeof getAnswersResponseSchema>;

// GET /forms/answers/labels
export const getAnswerLabelsResponseSchema = z
.object({
id: z.number(),
name: z.string(),
})
.array();

export type GetAnswerLabelsResponse = z.infer<
typeof getAnswerLabelsResponseSchema
>;

// GET /forms/answers/:answerId
export const getAnswerResponseSchema = z.object({
id: z.number(),
Expand Down
24 changes: 24 additions & 0 deletions src/app/api/answers/labels/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
'use server';

import { NextResponse } from 'next/server';
import { BACKEND_SERVER_URL } from '@/env';
import { getCachedToken } from '@/user-token/mcToken';
import type { NextRequest } from 'next/server';

export async function GET(_: NextRequest) {
const token = await getCachedToken();
if (!token) {
return NextResponse.redirect('/');
}

const response = await fetch(`${BACKEND_SERVER_URL}/forms/answers/labels`, {
method: 'GET',
headers: {
Accept: 'application/json',
Authorization: `Bearer ${token}`,
},
cache: 'no-cache',
});

return NextResponse.json(await response.json(), { status: response.status });
}

0 comments on commit aad46f9

Please sign in to comment.