Persist program comparison notes
This commit is contained in:
62
src/App.jsx
62
src/App.jsx
@@ -1230,14 +1230,24 @@ function RelationPopup({ programs, onToggleRelation, onClose }) {
|
||||
function ProgramComparePopup({ programs, comparisons, onComparisonChange, onClose }) {
|
||||
const internalProgram = programs.find((program) => getProgramType(program.programType) === 'internal');
|
||||
const commercialProgram = programs.find((program) => getProgramType(program.programType) === 'commercial');
|
||||
const [leftProgramId, setLeftProgramId] = useState(internalProgram?.id ?? programs[0]?.id ?? '');
|
||||
const savedComparisons = comparisons.filter(
|
||||
(comparison) =>
|
||||
programs.some((program) => program.id === comparison.leftProgramId) &&
|
||||
programs.some((program) => program.id === comparison.rightProgramId) &&
|
||||
((comparison.stepMatches ?? []).some((match) => match.reason?.trim()) || comparison.note?.trim())
|
||||
).sort((left, right) => (right.updatedAt ?? '').localeCompare(left.updatedAt ?? ''));
|
||||
const [leftProgramId, setLeftProgramId] = useState(savedComparisons[0]?.leftProgramId ?? internalProgram?.id ?? programs[0]?.id ?? '');
|
||||
const [rightProgramId, setRightProgramId] = useState(
|
||||
commercialProgram?.id ?? programs.find((program) => program.id !== (internalProgram?.id ?? programs[0]?.id))?.id ?? ''
|
||||
savedComparisons[0]?.rightProgramId ??
|
||||
commercialProgram?.id ??
|
||||
programs.find((program) => program.id !== (internalProgram?.id ?? programs[0]?.id))?.id ??
|
||||
''
|
||||
);
|
||||
const leftProgram = programs.find((program) => program.id === leftProgramId);
|
||||
const rightProgram = programs.find((program) => program.id === rightProgramId);
|
||||
const comparison =
|
||||
comparisons.find((item) => item.leftProgramId === leftProgramId && item.rightProgramId === rightProgramId) ?? {};
|
||||
const hasSavedComparison = Boolean((comparison.stepMatches ?? []).some((match) => match.reason?.trim()) || comparison.note?.trim());
|
||||
const leftSteps = leftProgram?.steps ?? [];
|
||||
const rightSteps = rightProgram?.steps ?? [];
|
||||
const stepMatches = comparison.stepMatches ?? [];
|
||||
@@ -1255,6 +1265,11 @@ function ProgramComparePopup({ programs, comparisons, onComparisonChange, onClos
|
||||
const existingIndex = stepMatches.findIndex(
|
||||
(match) => String(match.leftStepIndex) === String(stepIndex) && String(match.rightStepIndex) === String(stepIndex)
|
||||
);
|
||||
if (!value.trim() && existingIndex >= 0) {
|
||||
updateComparison('stepMatches', stepMatches.filter((_, index) => index !== existingIndex));
|
||||
return;
|
||||
}
|
||||
if (!value.trim()) return;
|
||||
const nextMatch = {
|
||||
...(existingIndex >= 0 ? stepMatches[existingIndex] : {}),
|
||||
id: `step-${stepIndex}`,
|
||||
@@ -1270,6 +1285,9 @@ function ProgramComparePopup({ programs, comparisons, onComparisonChange, onClos
|
||||
);
|
||||
};
|
||||
const getStepLabel = (step, index) => `${index + 1}. ${step?.title ?? '-'}`;
|
||||
const getProgramName = (programId) => programs.find((program) => program.id === programId)?.name ?? programId;
|
||||
const getComparisonMemoCount = (savedComparison) =>
|
||||
(savedComparison.stepMatches ?? []).filter((match) => match.reason?.trim()).length;
|
||||
|
||||
const renderProgramSummary = (program) => {
|
||||
if (!program) return null;
|
||||
@@ -1357,6 +1375,38 @@ function ProgramComparePopup({ programs, comparisons, onComparisonChange, onClos
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{savedComparisons.length > 0 && (
|
||||
<div className="mt-3 rounded-3xl bg-white px-4 py-3 ring-1 ring-slate-100">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<span className="mr-1 text-[12px] font-black text-slate-500">저장된 비교</span>
|
||||
{savedComparisons.map((savedComparison) => {
|
||||
const active =
|
||||
savedComparison.leftProgramId === leftProgramId &&
|
||||
savedComparison.rightProgramId === rightProgramId;
|
||||
const memoCount = getComparisonMemoCount(savedComparison);
|
||||
return (
|
||||
<button
|
||||
key={`${savedComparison.leftProgramId}-${savedComparison.rightProgramId}`}
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setLeftProgramId(savedComparison.leftProgramId);
|
||||
setRightProgramId(savedComparison.rightProgramId);
|
||||
}}
|
||||
className={`rounded-full px-3 py-1.5 text-[12px] font-black ring-1 transition ${
|
||||
active
|
||||
? 'bg-slate-950 text-white ring-slate-950'
|
||||
: 'bg-slate-50 text-slate-600 ring-slate-200 hover:bg-white'
|
||||
}`}
|
||||
>
|
||||
{getProgramName(savedComparison.leftProgramId)} ↔ {getProgramName(savedComparison.rightProgramId)}
|
||||
{memoCount > 0 ? ` · ${memoCount}개 메모` : ''}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mt-4 grid gap-4 lg:grid-cols-2">
|
||||
{renderProgramSummary(leftProgram)}
|
||||
{renderProgramSummary(rightProgram)}
|
||||
@@ -1368,6 +1418,7 @@ function ProgramComparePopup({ programs, comparisons, onComparisonChange, onClos
|
||||
<h3 className="text-base font-black text-slate-950">전체 스텝 1:1 비교</h3>
|
||||
<p className="mt-1 text-[12px] font-bold text-slate-500">
|
||||
두 프로그램의 스텝을 전부 펼친 뒤, 가운데에 해당 스텝에서 상용 프로그램을 쓰는 이유를 적습니다.
|
||||
{hasSavedComparison ? ' 저장된 비교 내용을 불러왔습니다.' : ''}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -2162,11 +2213,18 @@ export default function App() {
|
||||
...(comparisonIndex >= 0 ? comparisons[comparisonIndex] : {}),
|
||||
leftProgramId,
|
||||
rightProgramId,
|
||||
updatedAt: new Date().toISOString(),
|
||||
[field]: value
|
||||
};
|
||||
const hasComparisonContent =
|
||||
(nextComparison.stepMatches ?? []).some((match) => match.reason?.trim()) ||
|
||||
nextComparison.note?.trim();
|
||||
return {
|
||||
...current,
|
||||
comparisons:
|
||||
!hasComparisonContent
|
||||
? comparisons.filter((_, index) => index !== comparisonIndex)
|
||||
:
|
||||
comparisonIndex >= 0
|
||||
? comparisons.map((comparison, index) => (index === comparisonIndex ? nextComparison : comparison))
|
||||
: [...comparisons, nextComparison]
|
||||
|
||||
Reference in New Issue
Block a user