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:
@ -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',
|
||||
|
||||
@ -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;
|
||||
|
||||
Reference in New Issue
Block a user