Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .Jules/palette.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 2025-02-14 - ResponsiveConfirmDialog for Destructive Actions
**Learning:** Destructive actions (like Delete) implemented with custom hardcoded modals lack standard accessibility attributes (`role="dialog"`, `aria-modal`, etc.) and mobile responsiveness (like bottom sheets). This app has a `ResponsiveConfirmDialog` component designed specifically for this purpose, but it was not being utilized uniformly.
**Action:** Always use `ResponsiveConfirmDialog` for destructive confirmation prompts (such as `DeleteResumeModal`) to ensure a consistent, accessible, and mobile-friendly UX that prevents accidental data loss.
## 2026-03-25 - Custom Modal Icon Buttons
**Learning:** Custom modals often implement manual close buttons (e.g., `XMarkIcon`) that lack native `aria-label`s and `focus-visible` styles against dark backgrounds.
**Action:** Always verify that all icon-only buttons in custom modal headers receive explicit `aria-label`s and `focus-visible:ring-white` (or contrasting color) combined with `focus:outline-none`.
24 changes: 13 additions & 11 deletions resume-builder-ui/src/components/UploadResumeModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,18 @@ export function UploadResumeModal({
}: UploadResumeModalProps) {
const { parseResume, parsing, progress, error } = useResumeParser();
const [dragActive, setDragActive] = useState(false);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const [parseResult, setParseResult] = useState<any>(null);
Comment on lines +25 to 26
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

While disabling the ESLint rule for no-explicit-any makes the linter pass, it's preferable to define a specific type for the parseResult state. This improves type safety, readability, and long-term maintainability of the component.

I suggest defining a local ParseResult interface with the properties you're using from the parser's response. You can add this interface definition before the UploadResumeModal component:

interface ParseResult {
  yaml: string;
  confidence: number;
  warnings: string[];
  cached: boolean;
  ui_message: {
    title: string;
    description: string;
    type: 'success' | 'warning';
  };
}

Then, you can use this type in your useState hook and remove the eslint-disable comment.

Suggested change
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const [parseResult, setParseResult] = useState<any>(null);
const [parseResult, setParseResult] = useState<ParseResult | null>(null);


const handleFileUpload = useCallback(async (file: File) => {
try {
const result = await parseResume(file);
setParseResult(result);
} catch (err) {
console.error('Parse error:', err);
}
}, [parseResume]);

const handleDrag = useCallback((e: React.DragEvent) => {
e.preventDefault();
e.stopPropagation();
Expand All @@ -45,7 +55,7 @@ export function UploadResumeModal({
await handleFileUpload(file);
}
},
[]
[handleFileUpload]
);

const handleFileInput = async (
Expand All @@ -59,15 +69,6 @@ export function UploadResumeModal({
e.target.value = '';
};

const handleFileUpload = async (file: File) => {
try {
const result = await parseResume(file);
setParseResult(result);
} catch (err) {
console.error('Parse error:', err);
}
};

const handleContinue = () => {
if (parseResult) {
onSuccess(
Expand Down Expand Up @@ -99,7 +100,8 @@ export function UploadResumeModal({
</div>
<button
onClick={handleCloseModal}
className="text-white/80 hover:text-white transition-colors"
className="text-white/80 hover:text-white transition-colors p-1 rounded-lg focus:outline-none focus-visible:ring-2 focus-visible:ring-white"
aria-label="Close modal"
>
<XMarkIcon className="w-6 h-6" />
</button>
Expand Down
Loading