Fix/csv import (#1397)

* feat: add ability to enable or disable header selection

* feat: limit to max of 200 records for now

* fix: bigger modal

* feat: add missing standard fields for company

* fix: person fields

* feat: add hotkeys on dialog

* feat: mobile device

* fix: company import error

* fix: csv import crash

* fix: use scoped hotkey
This commit is contained in:
Jérémy M
2023-09-04 11:50:12 +02:00
committed by GitHub
parent f29d843db9
commit c0cb3a47f3
19 changed files with 213 additions and 86 deletions

View File

@ -3,12 +3,7 @@ import { v4 as uuidv4 } from 'uuid';
import { useSpreadsheetImport } from '@/spreadsheet-import/hooks/useSpreadsheetImport';
import { SpreadsheetOptions } from '@/spreadsheet-import/types';
import { useSnackBar } from '@/ui/snack-bar/hooks/useSnackBar';
import { useUpsertEntityTableItems } from '@/ui/table/hooks/useUpsertEntityTableItems';
import { useUpsertTableRowIds } from '@/ui/table/hooks/useUpsertTableRowIds';
import {
GetPeopleDocument,
useInsertManyCompanyMutation,
} from '~/generated/graphql';
import { useInsertManyCompanyMutation } from '~/generated/graphql';
import { fieldsForCompany } from '../utils/fieldsForCompany';
@ -16,8 +11,6 @@ export type FieldCompanyMapping = (typeof fieldsForCompany)[number]['key'];
export function useSpreadsheetCompanyImport() {
const { openSpreadsheetImport } = useSpreadsheetImport<FieldCompanyMapping>();
const upsertEntityTableItems = useUpsertEntityTableItems();
const upsertTableRowIds = useUpsertTableRowIds();
const { enqueueSnackBar } = useSnackBar();
const [createManyCompany] = useInsertManyCompanyMutation();
@ -34,11 +27,11 @@ export function useSpreadsheetCompanyImport() {
// TODO: Add better type checking in spreadsheet import later
const createInputs = data.validData.map((company) => ({
id: uuidv4(),
name: company.name as string,
domainName: company.domainName as string,
address: company.address as string,
employees: parseInt(company.employees as string, 10),
linkedinUrl: company.linkedinUrl as string | undefined,
name: (company.name ?? '') as string,
domainName: (company.domainName ?? '') as string,
address: (company.address ?? '') as string,
employees: parseInt((company.employees ?? '') as string, 10),
linkedinUrl: (company.linkedinUrl ?? '') as string | undefined,
}));
try {
@ -46,15 +39,12 @@ export function useSpreadsheetCompanyImport() {
variables: {
data: createInputs,
},
refetchQueries: [GetPeopleDocument],
refetchQueries: 'active',
});
if (result.errors) {
throw result.errors;
}
upsertTableRowIds(createInputs.map((company) => company.id));
upsertEntityTableItems(createInputs);
} catch (error: any) {
enqueueSnackBar(error?.message || 'Something went wrong', {
variant: 'error',

View File

@ -1,8 +1,11 @@
import {
IconBrandLinkedin,
IconBrandX,
IconBuildingSkyscraper,
IconMail,
IconMap,
IconMoneybag,
IconTarget,
IconUsers,
} from '@/ui/icon';
@ -16,13 +19,6 @@ export const fieldsForCompany = [
type: 'input',
},
example: 'Tim',
validations: [
{
rule: 'required',
errorMessage: 'Name is required',
level: 'error',
},
],
},
{
icon: <IconMail />,
@ -33,13 +29,6 @@ export const fieldsForCompany = [
type: 'input',
},
example: 'apple.dev',
validations: [
{
rule: 'required',
errorMessage: 'Domain name is required',
level: 'error',
},
],
},
{
icon: <IconBrandLinkedin />,
@ -51,6 +40,61 @@ export const fieldsForCompany = [
},
example: 'https://www.linkedin.com/in/apple',
},
{
icon: <IconMoneybag />,
label: 'ARR',
key: 'annualRecurringRevenue',
alternateMatches: [
'arr',
'annual revenue',
'revenue',
'recurring revenue',
'annual recurring revenue',
],
fieldType: {
type: 'input',
},
validation: [
{
regex: /^(\d+)?$/,
errorMessage: 'Annual recurring revenue must be a number',
level: 'error',
},
],
example: '1000000',
},
{
icon: <IconTarget />,
label: 'ICP',
key: 'idealCustomerProfile',
alternateMatches: [
'icp',
'ideal profile',
'ideal customer profile',
'ideal customer',
],
fieldType: {
type: 'input',
},
validation: [
{
regex: /^(true|false)?$/,
errorMessage: 'Ideal custoner profile must be a boolean',
level: 'error',
},
],
example: 'true/false',
},
{
icon: <IconBrandX />,
label: 'x URL',
key: 'xUrl',
alternateMatches: ['x', 'twitter', 'twitter url', 'x url'],
fieldType: {
type: 'input',
},
example: 'https://x.com/tim_cook',
},
{
icon: <IconMap />,
label: 'Address',
@ -59,13 +103,6 @@ export const fieldsForCompany = [
type: 'input',
},
example: 'Maple street',
validations: [
{
rule: 'required',
errorMessage: 'Address is required',
level: 'error',
},
],
},
{
icon: <IconUsers />,
@ -75,6 +112,13 @@ export const fieldsForCompany = [
fieldType: {
type: 'input',
},
validation: [
{
regex: /^\d+$/,
errorMessage: 'Employees must be a number',
level: 'error',
},
],
example: '150',
},
] as const;