[as] chore: 행정지원 메뉴 수정
This commit is contained in:
@@ -6,6 +6,7 @@ import { Paperclip } from "lucide-react";
|
||||
|
||||
import { PROXY_HOST } from "@/shared/config";
|
||||
import { dayjs, getDefaultFileKey, useTus } from "@/shared/lib";
|
||||
import { TextShimmer } from "@/shared/ui";
|
||||
import { Field, FieldLabel, FieldSet } from "@/shared/ui/field";
|
||||
import { attachService } from "@/entities/attach";
|
||||
import type { DesignCnstnRvwOpnnResponseDto } from "@/entities/design-cnstn";
|
||||
@@ -240,7 +241,9 @@ const TechReviewOpinionSection = forwardRef<
|
||||
<TableCell>
|
||||
{uploadedFile ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xl">{uploadedFile.fileName}</span>
|
||||
<TextShimmer className="text-xl" active={uploading}>
|
||||
{uploadedFile.fileName}
|
||||
</TextShimmer>
|
||||
<Button
|
||||
size="icon"
|
||||
onClick={(e) => {
|
||||
|
||||
@@ -46,12 +46,7 @@ function ChecklistTaskPanel({
|
||||
.forEach((row) => {
|
||||
nextResults[buildChecklistRowKey(row, selectedReviewStep)] = value;
|
||||
});
|
||||
return patchChecklistFormState(
|
||||
prev,
|
||||
{ results: nextResults },
|
||||
allRows,
|
||||
selectedReviewStep,
|
||||
);
|
||||
return patchChecklistFormState(prev, { results: nextResults }, allRows, selectedReviewStep);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -77,6 +72,7 @@ function ChecklistTaskPanel({
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
color="white"
|
||||
disabled={!isStepEditable}
|
||||
onClick={() => handleSelectAll("Y")}
|
||||
>
|
||||
@@ -87,9 +83,9 @@ function ChecklistTaskPanel({
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
color="gray"
|
||||
disabled={!isStepEditable}
|
||||
onClick={() => handleSelectAll("N")}
|
||||
className="!bg-destructive"
|
||||
>
|
||||
전체 아니오
|
||||
</Button>
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Paperclip } from "lucide-react";
|
||||
|
||||
import { PROXY_HOST } from "@/shared/config";
|
||||
import { dayjs, getDefaultFileKey, useTus } from "@/shared/lib";
|
||||
import { TextShimmer } from "@/shared/ui";
|
||||
import { Field, FieldLabel, FieldSet } from "@/shared/ui/field";
|
||||
import { attachService } from "@/entities/attach";
|
||||
import type { FnrsCnsltnRvwOpnnResponseDto } from "@/entities/fnrs-cnsltn";
|
||||
@@ -247,7 +248,9 @@ const TechReviewOpinionSection = forwardRef<
|
||||
<TableCell>
|
||||
{uploadedFile ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xl">{uploadedFile.fileName}</span>
|
||||
<TextShimmer className="text-xl" active={uploading}>
|
||||
{uploadedFile.fileName}
|
||||
</TextShimmer>
|
||||
<Button
|
||||
size="icon"
|
||||
onClick={(e) => {
|
||||
|
||||
@@ -45,12 +45,7 @@ function ChecklistTaskPanel({
|
||||
.forEach((row) => {
|
||||
nextResults[buildChecklistRowKey(row, selectedReviewStep)] = value;
|
||||
});
|
||||
return patchChecklistFormState(
|
||||
prev,
|
||||
{ results: nextResults },
|
||||
allRows,
|
||||
selectedReviewStep,
|
||||
);
|
||||
return patchChecklistFormState(prev, { results: nextResults }, allRows, selectedReviewStep);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -76,6 +71,7 @@ function ChecklistTaskPanel({
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
color="white"
|
||||
disabled={!isStepEditable}
|
||||
onClick={() => handleSelectAll("Y")}
|
||||
>
|
||||
@@ -86,9 +82,9 @@ function ChecklistTaskPanel({
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
color="gray"
|
||||
disabled={!isStepEditable}
|
||||
onClick={() => handleSelectAll("N")}
|
||||
className="!bg-destructive"
|
||||
>
|
||||
전체 아니오
|
||||
</Button>
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Paperclip } from "lucide-react";
|
||||
|
||||
import { PROXY_HOST } from "@/shared/config";
|
||||
import { dayjs, getDefaultFileKey, useTus } from "@/shared/lib";
|
||||
import { TextShimmer } from "@/shared/ui";
|
||||
import { Field, FieldLabel, FieldSet } from "@/shared/ui/field";
|
||||
import { attachService } from "@/entities/attach";
|
||||
import type { InstlSncnRvwOpnnResponseDto, ReviewStepCode } from "@/entities/instl-sncn";
|
||||
@@ -240,7 +241,9 @@ const TechReviewOpinionSection = forwardRef<
|
||||
<TableCell>
|
||||
{uploadedFile ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xl">{uploadedFile.fileName}</span>
|
||||
<TextShimmer className="text-xl" active={uploading}>
|
||||
{uploadedFile.fileName}
|
||||
</TextShimmer>
|
||||
<Button
|
||||
size="icon"
|
||||
onClick={(e) => {
|
||||
|
||||
@@ -49,23 +49,12 @@ export const REVIEW_STEP_LABELS: Record<ReviewStepCode, string> = {
|
||||
};
|
||||
|
||||
export const TASK_CODE_LABELS: Record<string, string> = {
|
||||
RE: "재이용수",
|
||||
SP: "하수관로",
|
||||
SF: "하수처리시설",
|
||||
MP: "변경",
|
||||
CP: "신규",
|
||||
CP: "부분변경",
|
||||
AP: "전체변경",
|
||||
MP: "병합",
|
||||
};
|
||||
|
||||
export const PBADMS_PROGRESS_ORDER = [
|
||||
"SV",
|
||||
"SL",
|
||||
"TA",
|
||||
"EP",
|
||||
"LE",
|
||||
"TP",
|
||||
"ER",
|
||||
"TE",
|
||||
] as const;
|
||||
export const PBADMS_PROGRESS_ORDER = ["SV", "SL", "TA", "EP", "LE", "TP", "ER", "TE"] as const;
|
||||
|
||||
export const ROLE_TO_REVIEW_STEP: Record<string, ReviewStepCode> = {
|
||||
ROLE_USER05: "LOCAL",
|
||||
|
||||
@@ -71,6 +71,7 @@ function ChecklistTaskPanel({
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
color="white"
|
||||
disabled={!isStepEditable}
|
||||
onClick={() => handleSelectAll("Y")}
|
||||
>
|
||||
@@ -81,9 +82,9 @@ function ChecklistTaskPanel({
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
color="gray"
|
||||
disabled={!isStepEditable}
|
||||
onClick={() => handleSelectAll("N")}
|
||||
className="!bg-destructive"
|
||||
>
|
||||
전체 아니오
|
||||
</Button>
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Paperclip } from "lucide-react";
|
||||
|
||||
import { PROXY_HOST } from "@/shared/config";
|
||||
import { dayjs, getDefaultFileKey, useTus } from "@/shared/lib";
|
||||
import { TextShimmer } from "@/shared/ui";
|
||||
import { Field, FieldLabel, FieldSet } from "@/shared/ui/field";
|
||||
import { attachService } from "@/entities/attach";
|
||||
import type { SewerBscPlanRvwOpnnResponseDto } from "@/entities/sewer-bsc-plan";
|
||||
@@ -247,7 +248,9 @@ const TechReviewOpinionSection = forwardRef<
|
||||
<TableCell>
|
||||
{uploadedFile ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xl">{uploadedFile.fileName}</span>
|
||||
<TextShimmer className="text-xl" active={uploading}>
|
||||
{uploadedFile.fileName}
|
||||
</TextShimmer>
|
||||
<Button
|
||||
size="icon"
|
||||
onClick={(e) => {
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Controller, useFieldArray, useFormContext, useWatch } from "react-hook-
|
||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||
|
||||
import { getDefaultFileKey, useTus } from "@/shared/lib";
|
||||
import { TextShimmer } from "@/shared/ui";
|
||||
import { Field } from "@/shared/ui/field";
|
||||
import { attachService } from "@/entities/attach";
|
||||
import { useFacilityList } from "@/entities/bns-if";
|
||||
@@ -319,7 +320,9 @@ function TmplntFacilityAttachments({
|
||||
<TableCell>
|
||||
{hasFile ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xl">{displayFileName}</span>
|
||||
<TextShimmer className="text-xl" active={uploading}>
|
||||
{displayFileName}
|
||||
</TextShimmer>
|
||||
<Button
|
||||
type="button"
|
||||
size="icon"
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
} from "@common/components";
|
||||
import { Button, Dialog, DialogClose, DialogContent, DialogFooter } from "@common/components";
|
||||
|
||||
import { useAlertStore } from "../lib/use-alert-store";
|
||||
|
||||
@@ -20,7 +14,7 @@ function AlertDialog() {
|
||||
<Dialog open={!!message} onOpenChange={handleOpenChange}>
|
||||
<DialogContent aria-describedby={undefined}>
|
||||
<div className="py-10">
|
||||
<p className="text-foreground whitespace-pre-line text-center text-[1.4rem]">
|
||||
<p className="whitespace-pre-line break-keep text-center text-[1.4rem] text-foreground">
|
||||
{message}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
export { PageLayout } from "./page-layout";
|
||||
export { NoData } from "./no-data";
|
||||
export { PageLayout } from "./page-layout";
|
||||
export type { TextShimmerProps } from "./text-shimmer";
|
||||
export { TEXT_SHIMMER_CLASS, TextShimmer } from "./text-shimmer";
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { cn } from "@common/components";
|
||||
|
||||
const TEXT_SHIMMER_CLASS =
|
||||
"animate-text-shimmer bg-gradient-to-r from-muted-foreground via-muted to-muted-foreground bg-[length:200%_100%] bg-clip-text text-transparent";
|
||||
|
||||
interface TextShimmerProps extends React.ComponentPropsWithoutRef<"span"> {
|
||||
active?: boolean;
|
||||
}
|
||||
|
||||
function TextShimmer({ active = false, className, children, ...props }: TextShimmerProps) {
|
||||
return (
|
||||
<span className={cn(className, active && TEXT_SHIMMER_CLASS)} {...props}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
export { TEXT_SHIMMER_CLASS, TextShimmer };
|
||||
export type { TextShimmerProps };
|
||||
@@ -8,6 +8,7 @@ import { useQueryClient } from "@tanstack/react-query";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import { useTus } from "@/shared/lib";
|
||||
import type { AtflMngClientResponseDto, EsntlAtchFileMngTreeResponseDto } from "@/shared/model";
|
||||
import { TextShimmer } from "@/shared/ui";
|
||||
import { attachService } from "@/entities/attach";
|
||||
import { useEsntlAtchFileMngTree } from "@/entities/esntl";
|
||||
import {
|
||||
@@ -413,20 +414,21 @@ function AttachmentsFormSection({
|
||||
|
||||
return (
|
||||
<div key={item.fileKey} className="flex items-center gap-2">
|
||||
<span className="text-xl">
|
||||
<TextShimmer className="text-xl" active={uploading}>
|
||||
{item.file?.name ?? item.fileName}
|
||||
</span>
|
||||
</TextShimmer>
|
||||
{!uploading && (
|
||||
<Button
|
||||
size="icon"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
void removeEssentialFile(file.esntlAtchFileId, idx);
|
||||
}}
|
||||
disabled={uploading}
|
||||
className="size-8 !bg-destructive"
|
||||
>
|
||||
<i className="diveicon di-x text-xs" aria-label="삭제" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
@@ -489,7 +491,9 @@ function AttachmentsFormSection({
|
||||
key={item.fileKey}
|
||||
className="flex items-center justify-between rounded-sm border p-2"
|
||||
>
|
||||
<span className="px-2 text-xl">{item.file?.name ?? item.fileName}</span>
|
||||
<TextShimmer className="px-2 text-xl" active={uploading}>
|
||||
{item.file?.name ?? item.fileName}
|
||||
</TextShimmer>
|
||||
<Button
|
||||
size="sm"
|
||||
color="gray"
|
||||
|
||||
@@ -25,7 +25,11 @@ import {
|
||||
TabsTrigger,
|
||||
} from "@common/components";
|
||||
|
||||
import { buildChecklistTabs, normalizeTaskSeComCdArray, syncCklstResultListFromTree } from "../lib/checklist-form-utils";
|
||||
import {
|
||||
buildChecklistTabs,
|
||||
normalizeTaskSeComCdArray,
|
||||
syncCklstResultListFromTree,
|
||||
} from "../lib/checklist-form-utils";
|
||||
|
||||
import { SectionCollapsible } from "./section-collapsible";
|
||||
|
||||
@@ -49,10 +53,7 @@ function ChecklistFormSection({ docSeComCd, fieldPrefix }: ChecklistFormSectionP
|
||||
const { watch, setValue, control, getValues } = useFormContext();
|
||||
const [activeTab, setActiveTab] = useState("");
|
||||
const taskSeComCd = watch(`${fieldPrefix}.taskSeComCd`) as string | string[] | undefined;
|
||||
const taskSeComCdArray = useMemo(
|
||||
() => normalizeTaskSeComCdArray(taskSeComCd),
|
||||
[taskSeComCd],
|
||||
);
|
||||
const taskSeComCdArray = useMemo(() => normalizeTaskSeComCdArray(taskSeComCd), [taskSeComCd]);
|
||||
const cklstResultList =
|
||||
(useWatch({ control, name: "cklstResultList" }) as CklstResultListItem[] | undefined) ?? [];
|
||||
|
||||
@@ -206,6 +207,7 @@ function ChecklistFormSection({ docSeComCd, fieldPrefix }: ChecklistFormSectionP
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
color="white"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
handleSelectAll(tab.code, "Y");
|
||||
@@ -218,11 +220,11 @@ function ChecklistFormSection({ docSeComCd, fieldPrefix }: ChecklistFormSectionP
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
color="gray"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
handleSelectAll(tab.code, "N");
|
||||
}}
|
||||
className="!bg-destructive"
|
||||
>
|
||||
전체 아니오
|
||||
</Button>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useEffect, useMemo, useState } from "react";
|
||||
import { Controller, useFormContext, useWatch } from "react-hook-form";
|
||||
|
||||
import { getDefaultFileKey, useTus } from "@/shared/lib";
|
||||
import { TextShimmer } from "@/shared/ui";
|
||||
import { Field } from "@/shared/ui/field";
|
||||
import { useAcntgSeMngTree } from "@/entities/acntg";
|
||||
import type { AtflMngClientResponseDto } from "@/entities/fnrs-cnsltn";
|
||||
@@ -257,12 +258,18 @@ function FnrsSharFormSection({ initialSharTree, initialSharAtchFiles }: FnrsShar
|
||||
<div className="mt-6 px-2 pb-2">
|
||||
<h3 className="mb-2 text-xl font-semibold">첨부파일</h3>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
{isSharUploading && uploadedFileName ? (
|
||||
<TextShimmer className="max-w-lg text-xl" active>
|
||||
{uploadedFileName}
|
||||
</TextShimmer>
|
||||
) : (
|
||||
<Input
|
||||
value={uploadedFileName}
|
||||
readOnly
|
||||
placeholder="총사업비 신청서(.hwp) 파일을 등록해주세요."
|
||||
className="max-w-lg rounded-sm"
|
||||
/>
|
||||
)}
|
||||
<Button type="button" color="white" disabled={isSharUploading} asChild>
|
||||
<label className="cursor-pointer">
|
||||
첨부파일
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { useEffect, useId, useState } from "react";
|
||||
|
||||
import { getDefaultFileKey, useTus } from "@/shared/lib";
|
||||
import { TextShimmer } from "@/shared/ui";
|
||||
import { attachService } from "@/entities/attach";
|
||||
import { CodeSelect } from "@/entities/code";
|
||||
import {
|
||||
@@ -269,7 +270,9 @@ function SplmntDmndDialog({
|
||||
<div className="flex items-center gap-2">
|
||||
{row.uploadedFile ? (
|
||||
<div className="flex items-stretch gap-2">
|
||||
<span className="text-xl">{row.uploadedFile.fileName}</span>
|
||||
<TextShimmer className="text-xl" active={uploading}>
|
||||
{row.uploadedFile.fileName}
|
||||
</TextShimmer>
|
||||
<Button
|
||||
type="button"
|
||||
size="icon"
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Controller, useFormContext, useWatch } from "react-hook-form";
|
||||
import { Paperclip } from "lucide-react";
|
||||
|
||||
import { dayjs, getDefaultFileKey, useTus } from "@/shared/lib";
|
||||
import { TextShimmer } from "@/shared/ui";
|
||||
import { attachService, useDownloadAttachmentByAtflCd } from "@/entities/attach";
|
||||
import {
|
||||
Badge,
|
||||
@@ -272,7 +273,9 @@ function SplmntDmndFormSection({ readOnly = false }: SplmntDmndFormSectionProps)
|
||||
{uploaded.fileName}
|
||||
</a>
|
||||
) : (
|
||||
<span className="text-xl">{uploaded.fileName}</span>
|
||||
<TextShimmer className="text-xl" active={uploading}>
|
||||
{uploaded.fileName}
|
||||
</TextShimmer>
|
||||
)}
|
||||
{!isRowReadOnly ? (
|
||||
<Button
|
||||
|
||||
@@ -83,12 +83,17 @@ export default {
|
||||
from: { transform: "translate(0,0) rotate(0deg)" },
|
||||
to: { transform: "translate(0,0) rotate(360deg)" },
|
||||
},
|
||||
"text-shimmer": {
|
||||
"0%": { backgroundPosition: "200% center" },
|
||||
"100%": { backgroundPosition: "-200% center" },
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
"accordion-down": "accordion-down 0.2s ease-out",
|
||||
"accordion-up": "accordion-up 0.2s ease-out",
|
||||
"spin-parent": "spin-parent 6s linear infinite",
|
||||
"spin-child": "spin-child 1s ease-in-out infinite",
|
||||
"text-shimmer": "text-shimmer 1.5s linear infinite",
|
||||
},
|
||||
backgroundImage: {
|
||||
"gradient-blue": "linear-gradient(.25turn, #2094fa, #00e5dd)",
|
||||
|
||||
Reference in New Issue
Block a user