generate-import-modal — automated Excel import modal generation generate-import-modal, ijw-Calander, community, automated Excel import modal generation, ide skills, generate-import-modal install, Claude Code, Cursor, Windsurf

v1.0.0
GitHub

About this Skill

Perfect for Frontend Agents needing automated Excel import modal generation with TypeScript and React hooks. generate-import-modal is a skill that automatically generates Excel import modals based on project standards, including modal components, parser functions, and TypeScript interfaces.

Features

Generates modal components using the useExcelImport hook
Creates parser functions for xlsx field mapping and normalization
Defines TypeScript interfaces for parsed rows
Provides guidance on integrating with parent components
Supports refactoring existing import modals to use the useExcelImport hook

# Core Topics

BIGSHOL BIGSHOL
[0]
[0]
Updated: 3/6/2026

Agent Capability Analysis

The generate-import-modal skill by BIGSHOL is an open-source community AI agent skill for Claude Code and other IDE workflows, helping agents execute tasks with better context, repeatability, and domain-specific guidance. Optimized for automated Excel import modal generation, generate-import-modal install.

Ideal Agent Persona

Perfect for Frontend Agents needing automated Excel import modal generation with TypeScript and React hooks.

Core Value

Empowers agents to create standardized Excel import modals with automatically generated modal components, parser functions, and TypeScript interfaces, streamlining the import process with `useExcelImport` hooks and xlsx field mapping.

Capabilities Granted for generate-import-modal

Automating Excel import modal creation for new domains
Refactoring existing import modals to use `useExcelImport` hooks
Generating TypeScript interfaces for parsed Excel data
Integrating import modals with parent components for seamless import functionality

! Prerequisites & Limits

  • Requires React and TypeScript project setup
  • Limited to Excel import functionality
  • Dependent on `hooks/useExcelImport.ts` and related component files
Labs Demo

Browser Sandbox Environment

⚡️ Ready to unleash?

Experience this Agent in a zero-setup browser environment powered by WebContainers. No installation required.

Boot Container Sandbox

generate-import-modal

Install generate-import-modal, an AI agent skill for AI agent workflows and automation. Works with Claude Code, Cursor, and Windsurf with one-command setup.

SKILL.md
Readonly

Purpose

새로운 Excel 가져오기 모달을 프로젝트 표준 패턴에 맞춰 자동 생성합니다:

  1. 모달 컴포넌트 생성useExcelImport 훅을 사용하는 가져오기 모달
  2. 파서 함수 생성 — xlsx 필드 매핑 및 정규화 로직
  3. 타입 정의 — 파싱된 행의 TypeScript 인터페이스
  4. 부모 컴포넌트 연동 안내 — 모달 열기/닫기 및 onImport 콜백 연결

When to Run

  • 새 도메인에 Excel 가져오기 기능을 추가할 때
  • 기존 가져오기 모달을 useExcelImport 훅 기반으로 리팩토링할 때
FilePurpose
hooks/useExcelImport.tsExcel 가져오기 공통 훅 (파일 읽기, 상태 관리, 가져오기 실행)
components/Textbooks/TextbookImportModal.tsx참조 구현: 교재 수납 가져오기
components/Billing/BillingImportModal.tsx참조 구현: 수납 데이터 가져오기
components/StudentManagement/StudentMigrationModal.tsx참조 구현: 학생 마이그레이션
utils/studentMatching.ts학생 매칭 유틸 (가져오기 시 학생 DB 매칭이 필요한 경우 사용)

Workflow

Step 1: 사용자 입력 수집

AskUserQuestion을 사용하여 다음을 확인합니다:

  1. 도메인 이름 (예: attendance, homework, shuttle)
  2. Excel 필드 매핑 — 어떤 열을 읽을지 (예: 이름, 학년, 학교, 점수)
  3. 필터 조건 (선택) — 특정 행만 가져올지 (예: 구분 === '교재')
  4. 학생 매칭 필요 여부studentMatching.ts 연동 필요 여부
  5. 소속 탭 — 이 모달이 열리는 탭 컴포넌트 이름

Step 2: 타입 정의 생성

파싱된 행의 인터페이스를 모달 파일 상단에 정의합니다:

typescript
1export interface <PascalCase>ImportRow { 2 // 사용자가 지정한 필드들 3 studentName: string; 4 grade: string; 5 // ... 6 // 학생 매칭이 필요한 경우: 7 matched: boolean; 8 studentId?: string; 9}

Step 3: 모달 컴포넌트 생성

파일: components/<PascalCase>/<PascalCase>ImportModal.tsx

프로젝트 표준 구조:

tsx
1import React, { useMemo } from 'react'; 2import { X, Upload, FileSpreadsheet, Loader2, AlertCircle, Check, RotateCcw, Eye } from 'lucide-react'; 3import { useExcelImport } from '../../hooks/useExcelImport'; 4 5// 1. 타입 정의 6export interface <PascalCase>ImportRow { 7 // ...fields 8} 9 10// 2. Props 정의 11interface <PascalCase>ImportModalProps { 12 isOpen: boolean; 13 onClose: () => void; 14 onImport: (rows: <PascalCase>ImportRow[]) => Promise<{ added: number; skipped: number }>; 15 // 학생 매칭이 필요한 경우: 16 // studentIds?: Set<string>; 17} 18 19// 3. 파서 함수 (또는 컴포넌트 내부 useCallback) 20function parse<PascalCase>Rows(rows: Record<string, any>[]): <PascalCase>ImportRow[] { 21 return rows 22 // .filter(row => ...) // 필터 조건이 있는 경우 23 .map(row => ({ 24 // 필드 매핑 25 })); 26} 27 28// 4. 컴포넌트 29export const <PascalCase>ImportModal: React.FC<<PascalCase>ImportModalProps> = ({ 30 isOpen, 31 onClose, 32 onImport, 33}) => { 34 const { 35 fileInputRef, 36 parsedData, 37 fileName, 38 isImporting, 39 importResult, 40 handleFileChange, 41 handleImport, 42 handleReset, 43 openFileDialog, 44 isParsed, 45 isComplete, 46 } = useExcelImport({ 47 parser: parse<PascalCase>Rows, 48 onImport, 49 }); 50 51 // 통계 요약 (useMemo) 52 const summary = useMemo(() => { 53 if (!isParsed) return null; 54 return { 55 totalRecords: parsedData.length, 56 // ... 도메인별 통계 57 }; 58 }, [parsedData, isParsed]); 59 60 if (!isOpen) return null; 61 62 return ( 63 <div className="fixed inset-0 bg-black/50 flex items-start justify-center pt-[8vh] z-[100]" onClick={onClose}> 64 <div className="bg-white rounded-sm w-full max-w-2xl max-h-[85vh] flex flex-col overflow-hidden" onClick={e => e.stopPropagation()}> 65 {/* Header */} 66 <div className="flex items-center justify-between px-3 py-2 border-b border-gray-200"> 67 <h2 className="text-sm font-bold text-primary flex items-center gap-2"> 68 <FileSpreadsheet size={18} className="text-emerald-600" /> 69 <도메인명> 데이터 가져오기 70 </h2> 71 <button onClick={onClose} className="p-1 rounded-sm hover:bg-gray-100 text-gray-400 hover:text-gray-600"> 72 <X size={18} /> 73 </button> 74 </div> 75 76 {/* Body */} 77 <div className="flex-1 overflow-auto p-6 space-y-2"> 78 {/* 파일 업로드 섹션 */} 79 <div className="bg-white border border-gray-200 overflow-hidden"> 80 <div className="flex items-center gap-1 px-2 py-1.5 bg-gray-50 border-b border-gray-200"> 81 <Upload className="w-3 h-3 text-primary" /> 82 <h3 className="text-primary font-bold text-xs">파일 업로드</h3> 83 </div> 84 <div className="p-3"> 85 <input ref={fileInputRef} type="file" accept=".xlsx,.xls" onChange={handleFileChange} className="hidden" /> 86 <div className="flex items-center gap-3"> 87 <button 88 onClick={openFileDialog} 89 className="flex items-center gap-2 px-4 py-2 border-2 border-dashed border-gray-300 rounded-sm hover:border-emerald-500 hover:bg-emerald-50 transition-colors text-sm" 90 > 91 <FileSpreadsheet className="w-4 h-4" /> 92 Excel 파일 선택 93 </button> 94 {fileName && <span className="text-sm text-gray-600 font-medium">{fileName}</span>} 95 </div> 96 </div> 97 </div> 98 99 {/* 데이터 미리보기 섹션 */} 100 {summary && ( 101 <div className="bg-white border border-gray-200 overflow-hidden"> 102 <div className="flex items-center gap-1 px-2 py-1.5 bg-gray-50 border-b border-gray-200"> 103 <Eye className="w-3 h-3 text-primary" /> 104 <h3 className="text-primary font-bold text-xs">데이터 미리보기</h3> 105 </div> 106 <div className="p-3 space-y-3"> 107 {/* 통계 카드 */} 108 <div className="grid grid-cols-2 md:grid-cols-3 gap-2 text-sm"> 109 {/* ... 도메인별 통계 카드 */} 110 </div> 111 112 {/* 미리보기 테이블 */} 113 <div className="border border-gray-200 rounded-sm overflow-hidden"> 114 <div className="bg-gray-50 px-2 py-1 border-b border-gray-200"> 115 <h4 className="text-xs font-medium text-gray-600">처음 15건 미리보기</h4> 116 </div> 117 <div className="overflow-x-auto"> 118 <table className="w-full text-xs"> 119 <thead className="bg-gray-50 border-b border-gray-200"> 120 <tr>{/* 도메인별 컬럼 헤더 */}</tr> 121 </thead> 122 <tbody className="divide-y divide-gray-100 bg-white"> 123 {parsedData.slice(0, 15).map((row, i) => ( 124 <tr key={i} className="hover:bg-gray-50"> 125 {/* 도메인별 컬럼 데이터 */} 126 </tr> 127 ))} 128 </tbody> 129 </table> 130 </div> 131 {parsedData.length > 15 && ( 132 <div className="bg-gray-50 px-2 py-1 border-t border-gray-200"> 133 <p className="text-xxs text-gray-400 text-center">... 외 {parsedData.length - 15}건 더 있음</p> 134 </div> 135 )} 136 </div> 137 </div> 138 </div> 139 )} 140 141 {/* 결과 섹션 */} 142 {importResult && ( 143 <div className="bg-white border border-gray-200 overflow-hidden"> 144 <div className="flex items-center gap-1 px-2 py-1.5 bg-gray-50 border-b border-gray-200"> 145 {importResult.success 146 ? <Check className="w-3 h-3 text-emerald-600" /> 147 : <AlertCircle className="w-3 h-3 text-red-600" />} 148 <h3 className={`font-bold text-xs ${importResult.success ? 'text-emerald-700' : 'text-red-700'}`}> 149 {importResult.success ? '가져오기 완료' : '가져오기 실패'} 150 </h3> 151 </div> 152 <div className={`p-3 ${importResult.success ? 'bg-emerald-50' : 'bg-red-50'}`}> 153 {importResult.success ? ( 154 <div className="flex items-center gap-2"> 155 <Check className="w-5 h-5 text-emerald-600 shrink-0" /> 156 <div className="text-sm text-emerald-700 font-medium"> 157 {importResult.added.toLocaleString()}건 추가 완료 158 {importResult.skipped > 0 && ( 159 <span className="text-gray-500 font-normal ml-1">(중복 {importResult.skipped.toLocaleString()}건 건너뜀)</span> 160 )} 161 </div> 162 </div> 163 ) : ( 164 <div className="flex items-start gap-2"> 165 <AlertCircle className="w-5 h-5 text-red-600 shrink-0 mt-0.5" /> 166 <span className="text-sm text-red-700 font-medium">데이터 가져오기에 실패했습니다.</span> 167 </div> 168 )} 169 </div> 170 </div> 171 )} 172 </div> 173 174 {/* Footer */} 175 <div className="flex gap-3 px-6 py-4 border-t bg-gray-50"> 176 {isComplete ? ( 177 <> 178 <button onClick={handleReset} className="flex-1 flex items-center justify-center gap-2 px-4 py-2 border border-gray-300 rounded-sm hover:bg-gray-100 text-sm font-medium"> 179 <RotateCcw className="w-4 h-4" /> 다른 파일 가져오기 180 </button> 181 <button onClick={onClose} className="flex-1 px-4 py-2 bg-emerald-600 text-white rounded-sm hover:bg-emerald-700 text-sm font-medium">닫기</button> 182 </> 183 ) : ( 184 <> 185 <button onClick={onClose} className="flex-1 px-4 py-2 border border-gray-300 rounded-sm hover:bg-gray-100 text-sm font-medium">취소</button> 186 <button 187 onClick={handleImport} 188 disabled={!isParsed || isImporting} 189 className="flex-1 flex items-center justify-center gap-2 px-4 py-2 bg-emerald-600 text-white rounded-sm hover:bg-emerald-700 disabled:opacity-50 disabled:cursor-not-allowed text-sm font-medium" 190 > 191 {isImporting ? ( 192 <><Loader2 className="w-4 h-4 animate-spin" /> 가져오는 중...</> 193 ) : ( 194 <><Upload className="w-4 h-4" /> {isParsed ? `${parsedData.length.toLocaleString()}건 가져오기` : '가져오기'}</> 195 )} 196 </button> 197 </> 198 )} 199 </div> 200 </div> 201 </div> 202 ); 203};

Step 4: barrel export 업데이트

해당 도메인의 index.ts에 export를 추가합니다:

typescript
1export { <PascalCase>ImportModal } from './<PascalCase>ImportModal';

Step 5: 부모 컴포넌트 연동 안내

가져오기 모달을 호출하는 부모 컴포넌트에서:

tsx
1// 1. state 추가 2const [isImportOpen, setIsImportOpen] = useState(false); 3 4// 2. onImport 콜백 (훅에서 mutation 함수를 가져와 사용) 5const handleImport = async (rows: <PascalCase>ImportRow[]) => { 6 // Firebase batch write or mutation 7 const batch = writeBatch(db); 8 // ... batch.set/update 9 await batch.commit(); 10 return { added: rows.length, skipped: 0 }; 11}; 12 13// 3. 버튼 추가 14<button onClick={() => setIsImportOpen(true)}> 15 xlsx 가져오기 16</button> 17 18// 4. 모달 렌더 19<<PascalCase>ImportModal 20 isOpen={isImportOpen} 21 onClose={() => setIsImportOpen(false)} 22 onImport={handleImport} 23/>

Step 6: 검증

  1. 컴포넌트 파일 존재 확인
  2. useExcelImport import 확인
  3. barrel export 존재 확인
  4. TypeScript 타입 오류 없는지 확인

Output Format

markdown
1## 가져오기 모달 생성 완료 2 3| 항목 | 상태 | 파일 | 4|------|------|------| 5| 타입 정의 | 생성됨 | `components/<Name>/<Name>ImportModal.tsx` (상단) | 6| 모달 컴포넌트 | 생성됨 | `components/<Name>/<Name>ImportModal.tsx` | 7| barrel export | 업데이트 | `components/<Name>/index.ts` | 8| useExcelImport | 연동됨 | `hooks/useExcelImport.ts` | 9 10필드 매핑: 11- `이름` → studentName (string) 12- `학년` → grade (string) 13- ... 14 15다음 단계: 161. 부모 컴포넌트에서 모달 열기/닫기 state 추가 172. `onImport` 콜백에서 Firebase batch write 구현 183. 통계 카드와 미리보기 테이블의 컬럼을 도메인에 맞게 커스터마이즈

Design Decisions

useExcelImport 훅 사용 이유

프로젝트에 이미 7개의 가져오기 모달이 존재하며, 모두 동일한 상태 관리 패턴을 반복합니다:

  • fileInputRef, parsedData, fileName, isImporting, importResult state
  • handleFileChange (xlsx 파싱), handleImport, handleReset 핸들러

useExcelImport 훅은 이 공통 로직을 캡슐화하여:

  • 새 모달 작성 시 코드량 60% 감소
  • 상태 관리 버그 방지 (검증된 패턴 재사용)
  • 일관된 UX (파일 선택 → 미리보기 → 가져오기 → 결과)

모달 UI 표준

모든 가져오기 모달은 동일한 4섹션 구조를 따릅니다:

  1. 헤더 — FileSpreadsheet 아이콘 + 도메인명 + 닫기 버튼
  2. 파일 업로드 — 점선 border 버튼 + hidden input
  3. 미리보기 — 통계 카드(grid) + 테이블(처음 15건)
  4. 푸터 — 완료 전: 취소/가져오기 | 완료 후: 다른 파일/닫기

색상 체계: emerald(성공), red(실패), gray(기본), blue(통계)

Exceptions

다음은 문제가 아닙니다:

  1. 통계 카드/테이블 컬럼이 TODO — 도메인별 커스터마이즈가 필요한 부분이므로 생성 후 수동 조정
  2. onImport에 Firebase 로직이 없는 것 — 가져오기 모달은 UI만 담당하고, 저장 로직은 부모/훅에서 구현
  3. 학생 매칭 미포함 — 학생 매칭이 필요한 경우에만 studentIds prop과 studentMatching.ts 유틸 연동

FAQ & Installation Steps

These questions and steps mirror the structured data on this page for better search understanding.

? Frequently Asked Questions

What is generate-import-modal?

Perfect for Frontend Agents needing automated Excel import modal generation with TypeScript and React hooks. generate-import-modal is a skill that automatically generates Excel import modals based on project standards, including modal components, parser functions, and TypeScript interfaces.

How do I install generate-import-modal?

Run the command: npx killer-skills add BIGSHOL/ijw-Calander/generate-import-modal. It works with Cursor, Windsurf, VS Code, Claude Code, and 19+ other IDEs.

What are the use cases for generate-import-modal?

Key use cases include: Automating Excel import modal creation for new domains, Refactoring existing import modals to use `useExcelImport` hooks, Generating TypeScript interfaces for parsed Excel data, Integrating import modals with parent components for seamless import functionality.

Which IDEs are compatible with generate-import-modal?

This skill is compatible with Cursor, Windsurf, VS Code, Trae, Claude Code, OpenClaw, Aider, Codex, OpenCode, Goose, Cline, Roo Code, Kiro, Augment Code, Continue, GitHub Copilot, Sourcegraph Cody, and Amazon Q Developer. Use the Killer-Skills CLI for universal one-command installation.

Are there any limitations for generate-import-modal?

Requires React and TypeScript project setup. Limited to Excel import functionality. Dependent on `hooks/useExcelImport.ts` and related component files.

How To Install

  1. 1. Open your terminal

    Open the terminal or command line in your project directory.

  2. 2. Run the install command

    Run: npx killer-skills add BIGSHOL/ijw-Calander/generate-import-modal. The CLI will automatically detect your IDE or AI agent and configure the skill.

  3. 3. Start using the skill

    The skill is now active. Your AI agent can use generate-import-modal immediately in the current project.

Related Skills

Looking for an alternative to generate-import-modal or another community skill for your workflow? Explore these related open-source skills.

View All

widget-generator

Logo of f
f

f.k.a. Awesome ChatGPT Prompts. Share, discover, and collect prompts from the community. Free and open source — self-host for your organization with complete privacy.

149.6k
0
AI

flags

Logo of vercel
vercel

flags is a Next.js feature management skill that enables developers to efficiently add or modify framework feature flags, streamlining React application development.

138.4k
0
Browser

zustand

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
AI

data-fetching

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
AI