Skip to content

Commit e48d724

Browse files
committed
feat: add RepliesPage component and integrate with AdminFormDetailPage
1 parent b26fadd commit e48d724

File tree

6 files changed

+91
-39
lines changed

6 files changed

+91
-39
lines changed

src/features/form/components/AdminFormDetailPage.module.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@
5555
max-width: 25rem;
5656
}
5757

58+
.replies {
59+
max-width: 30rem;
60+
}
61+
5862
.design {
5963
max-width: 30rem;
6064
}

src/features/form/components/AdminFormDetailPage.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import styles from "./AdminFormDetailPage.module.css";
55
import { AdminFormDesignPage } from "./AdminFormDetailPages/DesignPage";
66
import { AdminFormEditPage } from "./AdminFormDetailPages/EditPage";
77
import { AdminFormInfoPage } from "./AdminFormDetailPages/InfoPage";
8+
import { AdminFormRepliesPage } from "./AdminFormDetailPages/RepliesPage";
89
import { AdminSectionEditPage } from "./AdminFormDetailPages/SectionEditPage";
910

1011
type TabType = "info" | "edit" | "reply" | "design";
@@ -63,7 +64,11 @@ export const AdminFormDetailPage = () => {
6364
<AdminSectionEditPage />
6465
</div>
6566
)}
66-
{activeTab === "reply" && <div>Reply Page Content</div>}
67+
{activeTab === "reply" && (
68+
<div className={styles.replies}>
69+
<AdminFormRepliesPage />
70+
</div>
71+
)}
6772
{activeTab === "design" && (
6873
<div className={styles.design}>
6974
<AdminFormDesignPage />

src/features/form/components/AdminFormDetailPages/SectionEditPage.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,12 @@ export const AdminSectionEditPage = () => {
151151
setQuestions(updatedQuestions);
152152
};
153153

154+
const handleToggleIsFromAnswer = (questionIndex: number) => {
155+
const updatedQuestions = [...questions];
156+
updatedQuestions[questionIndex].isFromAnswer = !updatedQuestions[questionIndex].isFromAnswer;
157+
setQuestions(updatedQuestions);
158+
};
159+
154160
return (
155161
<>
156162
<div className={styles.layout}>
@@ -183,6 +189,7 @@ export const AdminSectionEditPage = () => {
183189
onStartChange={newStart => handleStartChange(index, newStart)}
184190
onEndChange={newEnd => handleEndChange(index, newEnd)}
185191
onChangeIcon={newIcon => handleChangeIcon(index, newIcon)}
192+
onToggleIsFromAnswer={() => handleToggleIsFromAnswer(index)}
186193
/>
187194
))}
188195
</div>

src/features/form/components/AdminFormDetailPages/components/OptionsQuestion.module.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,9 @@
2222
color: var(--orange);
2323
padding: 0 0.5rem;
2424
}
25+
26+
.wrapper {
27+
display: flex;
28+
gap: 1rem;
29+
align-items: center;
30+
}

src/features/form/components/AdminFormDetailPages/components/OptionsQuestion.tsx

Lines changed: 62 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { Select } from "@/shared/components/Select/Select";
2+
import { Switch } from "@/shared/components/Switch/Switch";
13
import { X } from "lucide-react";
24
import type { Option } from "../types/option";
35
import { OptionsInput } from "./OptionsInput";
@@ -12,49 +14,71 @@ export interface OptionsQuestionProps {
1214
onAddOther: () => void;
1315
onRemove: (optionIndex: number) => void;
1416
onRemoveOther: () => void;
17+
onToggleIsFromAnswer: () => void;
1518
}
1619

1720
export const OptionsQuestion = (props: OptionsQuestionProps) => {
1821
return (
1922
<div className={styles.container}>
20-
{props.options.map((option, index) => {
21-
if (!option.isOther) {
22-
return (
23-
<div className={styles.optionWrapper}>
24-
<OptionsInput
25-
key={index}
26-
value={option.label}
27-
type={props.type}
28-
themeColor="--comment"
29-
variant="flushed"
30-
listLabel={`${index + 1}.`}
31-
className={styles.optionInput}
32-
autoFocus={index === props.options.length - 1 - props.options.filter(option => option.isOther).length}
33-
onChange={e => props.onChange(index, e.target.value)}
34-
/>
35-
{props.options.length > 1 && <X onClick={() => props.onRemove(index)} />}
36-
</div>
37-
);
38-
}
39-
if (option.isOther) {
40-
return (
41-
<div className={styles.optionWrapper}>
42-
<OptionsInput key="other" value="其他" type={props.type} variant="none" readOnly />
43-
{props.options.length > 1 && <X onClick={props.onRemoveOther} />}
44-
</div>
45-
);
46-
}
47-
})}
48-
<div className={styles.addOptions}>
49-
<OptionsInput value="新增選項" type={props.type} variant="none" onClick={props.onAdd} listLabel={`${props.options.length + 1}.`} readOnly className={styles.addOption} />
50-
{!props.options.some(option => option.isOther) && props.type !== "list" && (
51-
<>
52-
53-
<a className={styles.addOther} onClick={props.onAddOther}>
54-
新增其他
55-
</a>
56-
</>
57-
)}
23+
{!props.isFromAnswer && (
24+
<>
25+
{props.options.map((option, index) => {
26+
if (!option.isOther) {
27+
return (
28+
<div className={styles.optionWrapper}>
29+
<OptionsInput
30+
key={index}
31+
value={option.label}
32+
type={props.type}
33+
themeColor="--comment"
34+
variant="flushed"
35+
listLabel={`${index + 1}.`}
36+
className={styles.optionInput}
37+
autoFocus={index === props.options.length - 1 - props.options.filter(option => option.isOther).length}
38+
onChange={e => props.onChange(index, e.target.value)}
39+
/>
40+
{props.options.length > 1 && <X onClick={() => props.onRemove(index)} />}
41+
</div>
42+
);
43+
}
44+
if (option.isOther) {
45+
return (
46+
<div className={styles.optionWrapper}>
47+
<OptionsInput key="other" value="其他" type={props.type} variant="none" readOnly />
48+
{props.options.length > 1 && <X onClick={props.onRemoveOther} />}
49+
</div>
50+
);
51+
}
52+
})}
53+
<div className={styles.addOptions}>
54+
<OptionsInput value="新增選項" type={props.type} variant="none" onClick={props.onAdd} listLabel={`${props.options.length + 1}.`} readOnly className={styles.addOption} />
55+
{!props.options.some(option => option.isOther) && props.type !== "list" && (
56+
<>
57+
58+
<a className={styles.addOther} onClick={props.onAddOther}>
59+
新增其他
60+
</a>
61+
</>
62+
)}
63+
</div>
64+
</>
65+
)}
66+
{props.isFromAnswer && (
67+
<Select
68+
disabled
69+
placeholder="從回答選項中選擇"
70+
options={[
71+
{
72+
label: "區域A",
73+
value: "areaA"
74+
}
75+
]}
76+
value="areaA"
77+
/>
78+
)}
79+
<div className={styles.wrapper}>
80+
<p>問題來自答案</p>
81+
<Switch checked={props.isFromAnswer} onClick={props.onToggleIsFromAnswer} />
5882
</div>
5983
</div>
6084
);

src/features/form/components/AdminFormDetailPages/components/QuestionCard.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export interface QuestionCardProps {
2424
onStartChange?: (newStart: number) => void;
2525
onEndChange?: (newEnd: number) => void;
2626
onChangeIcon?: (newIcon: Question["icon"]) => void;
27+
onToggleIsFromAnswer?: () => void;
2728
}
2829

2930
type typeInfo = {
@@ -167,6 +168,11 @@ export const QuestionCard = (props: QuestionCardProps): ReactNode => {
167168
props.onRemoveOtherOption();
168169
}
169170
}}
171+
onToggleIsFromAnswer={() => {
172+
if (props.onToggleIsFromAnswer) {
173+
props.onToggleIsFromAnswer();
174+
}
175+
}}
170176
/>
171177
)}
172178
{question.type === "LINEAR_SCALE" && (

0 commit comments

Comments
 (0)