Style tweaks
This commit is contained in:
@@ -19,8 +19,7 @@ import {
|
|||||||
import { useQuery } from "@tanstack/react-query"
|
import { useQuery } from "@tanstack/react-query"
|
||||||
import config from "@/config"
|
import config from "@/config"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import { CheckCircle2, AlertCircle, InfoIcon, EyeIcon, EyeOffIcon, ArrowRightIcon, XIcon, FileIcon, LinkIcon } from "lucide-react"
|
import { CheckCircle2, AlertCircle, EyeIcon, EyeOffIcon, ArrowRightIcon, XIcon, FileSpreadsheetIcon, LinkIcon, FileIcon } from "lucide-react"
|
||||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"
|
|
||||||
import { Separator } from "@/components/ui/separator"
|
import { Separator } from "@/components/ui/separator"
|
||||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
||||||
import { Badge } from "@/components/ui/badge"
|
import { Badge } from "@/components/ui/badge"
|
||||||
@@ -110,7 +109,7 @@ export const MatchColumnsStep = <T extends string>({
|
|||||||
onBack,
|
onBack,
|
||||||
initialGlobalSelections
|
initialGlobalSelections
|
||||||
}: MatchColumnsProps<T>) => {
|
}: MatchColumnsProps<T>) => {
|
||||||
const dataExample = useMemo(() => data.slice(0, 3), [data]) // Show 3 sample rows
|
const dataExample = useMemo(() => data.slice(0, 5), [data]) // Show 5 sample rows
|
||||||
const { fields, autoMapHeaders, autoMapSelectValues, autoMapDistance, translations } = useRsi<T>()
|
const { fields, autoMapHeaders, autoMapSelectValues, autoMapDistance, translations } = useRsi<T>()
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
const [columns, setColumns] = useState<Columns<T>>(
|
const [columns, setColumns] = useState<Columns<T>>(
|
||||||
@@ -200,8 +199,6 @@ export const MatchColumnsStep = <T extends string>({
|
|||||||
});
|
});
|
||||||
}, [columns]);
|
}, [columns]);
|
||||||
|
|
||||||
// Get the first value from the sample data for a column
|
|
||||||
|
|
||||||
// Get mapped company value (if company is mapped to a column)
|
// Get mapped company value (if company is mapped to a column)
|
||||||
const mappedCompanyColumn = useMemo(() => findMappedColumnForField('company'), [findMappedColumnForField]);
|
const mappedCompanyColumn = useMemo(() => findMappedColumnForField('company'), [findMappedColumnForField]);
|
||||||
const mappedCompanyValue = useMemo(() => {
|
const mappedCompanyValue = useMemo(() => {
|
||||||
@@ -726,7 +723,7 @@ export const MatchColumnsStep = <T extends string>({
|
|||||||
<Popover>
|
<Popover>
|
||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<Button variant="ghost" size="icon" className="h-8 w-8">
|
<Button variant="ghost" size="icon" className="h-8 w-8">
|
||||||
<FileIcon className="h-4 w-4 text-muted-foreground" />
|
<FileSpreadsheetIcon className="h-4 w-4 text-muted-foreground" />
|
||||||
</Button>
|
</Button>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent side="right" align="start" className="w-[250px] p-0">
|
<PopoverContent side="right" align="start" className="w-[250px] p-0">
|
||||||
@@ -865,13 +862,13 @@ export const MatchColumnsStep = <T extends string>({
|
|||||||
{/* Left panel - Global selections & Required fields */}
|
{/* Left panel - Global selections & Required fields */}
|
||||||
<div className="lg:col-span-1 space-y-4">
|
<div className="lg:col-span-1 space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-lg font-medium mb-4">Global Settings</h3>
|
<h3 className="text-lg font-medium mb-0">Global Settings</h3>
|
||||||
<p className="text-sm text-muted-foreground mb-4">
|
<p className="text-sm text-muted-foreground mb-2">
|
||||||
Apply these values to all imported items
|
These values will be applied to all imported items
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="space-y-4">
|
<div className="space-y-2">
|
||||||
<div className="space-y-2">
|
<div className="space-y-1">
|
||||||
<label className="text-sm font-medium">Supplier</label>
|
<label className="text-sm font-medium">Supplier</label>
|
||||||
<Select
|
<Select
|
||||||
value={globalSelections.supplier}
|
value={globalSelections.supplier}
|
||||||
@@ -890,7 +887,7 @@ export const MatchColumnsStep = <T extends string>({
|
|||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-1">
|
||||||
<label className="text-sm font-medium">Company</label>
|
<label className="text-sm font-medium">Company</label>
|
||||||
<Select
|
<Select
|
||||||
value={globalSelections.company}
|
value={globalSelections.company}
|
||||||
@@ -916,7 +913,7 @@ export const MatchColumnsStep = <T extends string>({
|
|||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-1">
|
||||||
<label className="text-sm font-medium">Line</label>
|
<label className="text-sm font-medium">Line</label>
|
||||||
<Select
|
<Select
|
||||||
value={globalSelections.line}
|
value={globalSelections.line}
|
||||||
@@ -942,7 +939,7 @@ export const MatchColumnsStep = <T extends string>({
|
|||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-1">
|
||||||
<label className="text-sm font-medium">Sub Line</label>
|
<label className="text-sm font-medium">Sub Line</label>
|
||||||
<Select
|
<Select
|
||||||
value={globalSelections.subline}
|
value={globalSelections.subline}
|
||||||
@@ -964,22 +961,12 @@ export const MatchColumnsStep = <T extends string>({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Separator className="my-6" />
|
<Separator className="my-8" />
|
||||||
|
|
||||||
{/* Required Fields Section - Updated to show source column */}
|
{/* Required Fields Section - Updated to show source column */}
|
||||||
<div>
|
<div>
|
||||||
<div className="flex items-center gap-2 mb-4">
|
<div className="flex items-center gap-2 mb-4">
|
||||||
<h3 className="text-lg font-medium">Required Fields</h3>
|
<h3 className="text-lg font-medium">Matched Fields</h3>
|
||||||
<TooltipProvider>
|
|
||||||
<Tooltip>
|
|
||||||
<TooltipTrigger asChild>
|
|
||||||
<InfoIcon className="h-4 w-4 text-muted-foreground" />
|
|
||||||
</TooltipTrigger>
|
|
||||||
<TooltipContent>
|
|
||||||
<p className="max-w-xs">Map columns to required fields or set them globally</p>
|
|
||||||
</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
</TooltipProvider>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
@@ -1019,27 +1006,7 @@ export const MatchColumnsStep = <T extends string>({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Stats summary for column mapping */}
|
|
||||||
<div className="mt-6 pt-4">
|
|
||||||
<div className="flex flex-col gap-1">
|
|
||||||
<div className="flex justify-between">
|
|
||||||
<span className="text-sm">Columns total:</span>
|
|
||||||
<span className="text-sm font-medium">{columns.length}</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex justify-between">
|
|
||||||
<span className="text-sm">Mapped:</span>
|
|
||||||
<span className="text-sm font-medium">{matchedColumns.length}</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex justify-between">
|
|
||||||
<span className="text-sm">Ignored:</span>
|
|
||||||
<span className="text-sm font-medium">{ignoredColumns.length}</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex justify-between">
|
|
||||||
<span className="text-sm">Unmapped:</span>
|
|
||||||
<span className="text-sm font-medium">{unmatchedColumns.length}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Right panel - Column mapping interface */}
|
{/* Right panel - Column mapping interface */}
|
||||||
@@ -1075,7 +1042,7 @@ export const MatchColumnsStep = <T extends string>({
|
|||||||
<TableHeader className="sticky top-0 bg-muted z-10">
|
<TableHeader className="sticky top-0 bg-muted z-10">
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead className="w-1/3">Spreadsheet Column</TableHead>
|
<TableHead className="w-1/3">Spreadsheet Column</TableHead>
|
||||||
<TableHead className="w-12 text-center">Data</TableHead>
|
<TableHead className="w-12 text-center">Sample Data</TableHead>
|
||||||
<TableHead className="w-12"></TableHead>
|
<TableHead className="w-12"></TableHead>
|
||||||
<TableHead>Map To Field</TableHead>
|
<TableHead>Map To Field</TableHead>
|
||||||
<TableHead className="w-24 text-right">Action</TableHead>
|
<TableHead className="w-24 text-right">Action</TableHead>
|
||||||
|
|||||||
@@ -149,21 +149,24 @@ export const SelectHeaderStep = ({ data, onContinue, onBack }: SelectHeaderProps
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col h-[calc(100vh-9.5rem)]">
|
<div className="flex flex-col h-[calc(100vh-9.5rem)]">
|
||||||
<div className="px-8 py-6 bg-background">
|
<div className="px-8 py-6 bg-background flex justify-between items-end">
|
||||||
<h2 className="text-2xl font-semibold text-foreground">
|
<div>
|
||||||
{translations.selectHeaderStep.title}
|
<h2 className="text-2xl font-semibold text-foreground">
|
||||||
</h2>
|
{translations.selectHeaderStep.title}
|
||||||
|
</h2>
|
||||||
|
<p className="mt-1 text-sm text-muted-foreground">
|
||||||
|
Select the row that contains your column headers
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
variant="default"
|
||||||
|
size="sm"
|
||||||
|
onClick={discardEmptyAndDuplicateRows}
|
||||||
|
>
|
||||||
|
Remove Empty/Duplicates
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 flex flex-col min-h-0">
|
<div className="flex-1 flex flex-col min-h-0">
|
||||||
<div className="px-8 mb-4 flex justify-end">
|
|
||||||
<Button
|
|
||||||
variant="default"
|
|
||||||
size="sm"
|
|
||||||
onClick={discardEmptyAndDuplicateRows}
|
|
||||||
>
|
|
||||||
Remove Empty/Duplicates
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<div className="px-8 flex-1 overflow-auto">
|
<div className="px-8 flex-1 overflow-auto">
|
||||||
<SelectHeaderTable
|
<SelectHeaderTable
|
||||||
data={localData}
|
data={localData}
|
||||||
|
|||||||
@@ -40,15 +40,13 @@ export const SelectHeaderTable = ({ data, selectedRows, setSelectedRows }: Props
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rounded-md border p-3">
|
<div className="rounded-md border p-3">
|
||||||
<p className="mb-2 p-2 text-sm text-muted-foreground">
|
|
||||||
Select the row that contains your column headers
|
<div className="h-[calc(100vh-23rem)] overflow-auto">
|
||||||
</p>
|
|
||||||
<div className="h-[calc(100vh-27rem)] overflow-auto">
|
|
||||||
<Table className="relative w-full" style={{ tableLayout: 'fixed' }}>
|
<Table className="relative w-full" style={{ tableLayout: 'fixed' }}>
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
<TableRow className="grid" style={{ gridTemplateColumns }}>
|
<TableRow className="grid" style={{ gridTemplateColumns }}>
|
||||||
<TableHead className="sticky top-0 z-20 bg-background overflow-hidden">
|
<TableHead className="sticky top-0 z-20 bg-background overflow-hidden">
|
||||||
<div className="truncate">Select</div>
|
|
||||||
</TableHead>
|
</TableHead>
|
||||||
{columns.map((column) => (
|
{columns.map((column) => (
|
||||||
<TableHead
|
<TableHead
|
||||||
|
|||||||
@@ -30,7 +30,14 @@ export const Steps = () => {
|
|||||||
const onNext = (v: StepState) => {
|
const onNext = (v: StepState) => {
|
||||||
history.current.push(state)
|
history.current.push(state)
|
||||||
setState(v)
|
setState(v)
|
||||||
v.type !== StepType.selectSheet && setActiveStep(activeStep + 1)
|
|
||||||
|
if (v.type === StepType.validateData && 'isFromScratch' in v && v.isFromScratch) {
|
||||||
|
// If starting from scratch, jump directly to the validation step
|
||||||
|
const validationStepIndex = steps.indexOf('validationStep')
|
||||||
|
setActiveStep(validationStepIndex)
|
||||||
|
} else if (v.type !== StepType.selectSheet) {
|
||||||
|
setActiveStep(activeStep + 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -4,15 +4,16 @@ import { useRsi } from "../../hooks/useRsi"
|
|||||||
import { DropZone } from "./components/DropZone"
|
import { DropZone } from "./components/DropZone"
|
||||||
import { StepType } from "../UploadFlow"
|
import { StepType } from "../UploadFlow"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
|
import { Separator } from "@/components/ui/separator"
|
||||||
|
|
||||||
type UploadProps = {
|
type UploadProps = {
|
||||||
onContinue: (data: XLSX.WorkBook, file: File) => Promise<void>
|
onContinue: (data: XLSX.WorkBook, file: File) => Promise<void>
|
||||||
setInitialState?: (state: { type: StepType; data: any[] }) => void
|
setInitialState?: (state: { type: StepType; data: any[]; isFromScratch?: boolean }) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const UploadStep = ({ onContinue, setInitialState }: UploadProps) => {
|
export const UploadStep = ({ onContinue, setInitialState }: UploadProps) => {
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
const { translations, fields } = useRsi()
|
const { translations } = useRsi()
|
||||||
|
|
||||||
const handleOnContinue = useCallback(
|
const handleOnContinue = useCallback(
|
||||||
async (data: XLSX.WorkBook, file: File) => {
|
async (data: XLSX.WorkBook, file: File) => {
|
||||||
@@ -30,19 +31,18 @@ export const UploadStep = ({ onContinue, setInitialState }: UploadProps) => {
|
|||||||
}, [setInitialState])
|
}, [setInitialState])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-8 flex flex-col items-center max-w-xl mx-auto">
|
<div className="p-8">
|
||||||
<h2 className="text-3xl font-semibold mb-8 text-center">{translations.uploadStep.title}</h2>
|
<h2 className="text-3xl font-semibold mb-8 text-left">{translations.uploadStep.title}</h2>
|
||||||
|
|
||||||
<div className="w-full space-y-8">
|
<div className="max-w-xl mx-auto w-full space-y-8">
|
||||||
<div className="border rounded-lg p-6 flex flex-col items-center">
|
<div className="rounded-lg p-6 flex flex-col items-center">
|
||||||
<h3 className="text-lg font-medium mb-4">Upload spreadsheet file</h3>
|
|
||||||
<DropZone onContinue={handleOnContinue} isLoading={isLoading} />
|
<DropZone onContinue={handleOnContinue} isLoading={isLoading} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center justify-center">
|
<div className="flex items-center justify-center">
|
||||||
<div className="bg-muted h-px w-16"></div>
|
<Separator className="w-24" />
|
||||||
<span className="px-3 text-muted-foreground text-sm font-medium">OR</span>
|
<span className="px-3 text-muted-foreground text-sm font-medium">OR</span>
|
||||||
<div className="bg-muted h-px w-16"></div>
|
<Separator className="w-24" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
|
|||||||
@@ -2,25 +2,25 @@ import type { DeepPartial } from "ts-essentials"
|
|||||||
|
|
||||||
export const translations = {
|
export const translations = {
|
||||||
uploadStep: {
|
uploadStep: {
|
||||||
title: "Upload file",
|
title: "Upload File",
|
||||||
manifestTitle: "Data that we expect:",
|
manifestTitle: "Data that we expect:",
|
||||||
manifestDescription: "(You will have a chance to rename or remove columns in next steps)",
|
manifestDescription: "(You will have a chance to rename or remove columns in next steps)",
|
||||||
maxRecordsExceeded: (maxRecords: string) => `Too many records. Up to ${maxRecords} allowed`,
|
maxRecordsExceeded: (maxRecords: string) => `Too many records. Up to ${maxRecords} allowed`,
|
||||||
dropzone: {
|
dropzone: {
|
||||||
title: "Upload .xlsx, .xls or .csv file",
|
title: "Drop any .xlsx, .xls or .csv file here or click to select",
|
||||||
errorToastDescription: "upload rejected",
|
errorToastDescription: "upload rejected",
|
||||||
activeDropzoneTitle: "Drop file here...",
|
activeDropzoneTitle: "Drop file here...",
|
||||||
buttonTitle: "Select file",
|
buttonTitle: "Select file",
|
||||||
loadingTitle: "Processing...",
|
loadingTitle: "Processing...",
|
||||||
},
|
},
|
||||||
selectSheet: {
|
selectSheet: {
|
||||||
title: "Select the sheet to use",
|
title: "Select Which Sheet To Use",
|
||||||
nextButtonTitle: "Next",
|
nextButtonTitle: "Next",
|
||||||
backButtonTitle: "Back",
|
backButtonTitle: "Back",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
selectHeaderStep: {
|
selectHeaderStep: {
|
||||||
title: "Select header row",
|
title: "Select Header Row",
|
||||||
nextButtonTitle: "Next",
|
nextButtonTitle: "Next",
|
||||||
backButtonTitle: "Back",
|
backButtonTitle: "Back",
|
||||||
},
|
},
|
||||||
@@ -39,7 +39,7 @@ export const translations = {
|
|||||||
duplicateColumnWarningDescription: "Columns cannot duplicate",
|
duplicateColumnWarningDescription: "Columns cannot duplicate",
|
||||||
},
|
},
|
||||||
validationStep: {
|
validationStep: {
|
||||||
title: "Validate data",
|
title: "Validate Data",
|
||||||
nextButtonTitle: "Next",
|
nextButtonTitle: "Next",
|
||||||
backButtonTitle: "Back",
|
backButtonTitle: "Back",
|
||||||
noRowsMessage: "No data found",
|
noRowsMessage: "No data found",
|
||||||
|
|||||||
Reference in New Issue
Block a user