Skip to content
Open
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
2 changes: 1 addition & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CRM } from "@/atomic-crm/root/CRM";
import { CRM } from '@/atomic-crm/root/CRM';

/**
* Application entry point
Expand Down
278 changes: 147 additions & 131 deletions src/atomic-crm/companies/CompanyInputs.tsx
Original file line number Diff line number Diff line change
@@ -1,160 +1,176 @@
import {
ReferenceInput,
TextInput,
SelectInput,
ArrayInput,
SimpleFormIterator,
} from "@/components/admin";
import { Separator } from "@/components/ui/separator";
import { useIsMobile } from "@/hooks/use-mobile";
import { required, useRecordContext } from "ra-core";
import ImageEditorField from "../misc/ImageEditorField";
import { isLinkedinUrl } from "../misc/isLinkedInUrl";
import { useConfigurationContext } from "../root/ConfigurationContext";
import type { Company, Sale } from "../types";
import { sizes } from "./sizes";
ReferenceInput,
TextInput,
SelectInput,
ArrayInput,
SimpleFormIterator,
} from '@/components/admin';
import { Separator } from '@/components/ui/separator';
import { useIsMobile } from '@/hooks/use-mobile';
import { required, useRecordContext } from 'ra-core';
import ImageEditorField from '../misc/ImageEditorField';
import { isLinkedinUrl } from '../misc/isLinkedInUrl';
import { useConfigurationContext } from '../root/ConfigurationContext';
import type { Company, Sale } from '../types';
import { sizes } from './sizes';

const isUrl = (url: string) => {
if (!url) return;
const UrlRegex = new RegExp(
/^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([-.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/i,
);
if (!UrlRegex.test(url)) {
return "Must be a valid URL";
}
if (!url) return;
const UrlRegex = new RegExp(
/^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([-.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/i
);
if (!UrlRegex.test(url)) {
return 'Must be a valid URL';
}
};

export const CompanyInputs = () => {
const isMobile = useIsMobile();
const isMobile = useIsMobile();

return (
<div className="flex flex-col gap-4 p-1">
<CompanyDisplayInputs />
<div className={`flex gap-4 ${isMobile ? "flex-col" : "flex-row"}`}>
<div className="flex flex-col gap-8 flex-1">
<CompanyContactInputs />
<CompanyContextInputs />
return (
<div className="flex flex-col gap-4 p-1">
<CompanyDisplayInputs />
<div className={`flex gap-4 ${isMobile ? 'flex-col' : 'flex-row'}`}>
<div className="flex flex-col gap-8 flex-1">
<CompanyContactInputs />
<CompanyContextInputs />
</div>
<Separator orientation={isMobile ? 'horizontal' : 'vertical'} />
<div className="flex flex-col gap-8 flex-1">
<CompanyAddressInputs />
<CompanyAdditionalInformationInputs />
<CompanyAccountManagerInput />
</div>
</div>
</div>
<Separator orientation={isMobile ? "horizontal" : "vertical"} />
<div className="flex flex-col gap-8 flex-1">
<CompanyAddressInputs />
<CompanyAdditionalInformationInputs />
<CompanyAccountManagerInput />
</div>
</div>
</div>
);
);
};

const CompanyDisplayInputs = () => {
const record = useRecordContext<Company>();
return (
<div className="flex gap-4 flex-1 flex-row">
<ImageEditorField
source="logo"
type="avatar"
width={60}
height={60}
emptyText={record?.name.charAt(0)}
linkPosition="bottom"
/>
<TextInput
source="name"
className="w-full h-fit"
validate={required()}
helperText={false}
/>
</div>
);
const record = useRecordContext<Company>();
return (
<div className="flex gap-4 flex-1 flex-row">
<ImageEditorField
source="logo"
type="avatar"
width={60}
height={60}
emptyText={record?.name.charAt(0)}
linkPosition="bottom"
/>
<TextInput
source="name"
className="w-full h-fit"
validate={required()}
helperText={false}
/>
</div>
);
};

const CompanyContactInputs = () => {
return (
<div className="flex flex-col gap-4">
<h6 className="text-lg font-semibold">Contact</h6>
<TextInput source="website" helperText={false} validate={isUrl} />
<TextInput
source="linkedin_url"
helperText={false}
validate={isLinkedinUrl}
/>
<TextInput source="phone_number" helperText={false} />
</div>
);
return (
<div className="flex flex-col gap-4">
<h6 className="text-lg font-semibold">Contact</h6>
<TextInput
source="website"
helperText={false}
validate={isUrl}
labelInline
/>
<TextInput
source="linkedin_url"
helperText={false}
validate={isLinkedinUrl}
labelInline
/>
<TextInput source="phone_number" helperText={false} labelInline />
</div>
);
};

const CompanyContextInputs = () => {
const { companySectors } = useConfigurationContext();
return (
<div className="flex flex-col gap-4">
<h6 className="text-lg font-semibold">Context</h6>
<SelectInput
source="sector"
choices={companySectors.map((sector) => ({
id: sector,
name: sector,
}))}
helperText={false}
/>
<SelectInput source="size" choices={sizes} helperText={false} />
<TextInput source="revenue" helperText={false} />
<TextInput source="tax_identifier" helperText={false} />
</div>
);
const { companySectors } = useConfigurationContext();
return (
<div className="flex flex-col gap-4">
<h6 className="text-lg font-semibold">Context</h6>
<SelectInput
source="sector"
choices={companySectors.map(sector => ({
id: sector,
name: sector,
}))}
helperText={false}
labelInline
/>
<SelectInput
source="size"
choices={sizes}
helperText={false}
labelInline
/>
<TextInput source="revenue" helperText={false} labelInline />
<TextInput source="tax_identifier" helperText={false} labelInline />
</div>
);
};

const CompanyAddressInputs = () => {
return (
<div className="flex flex-col gap-4">
<h6 className="text-lg font-semibold">Address</h6>
<TextInput source="address" helperText={false} />
<TextInput source="city" helperText={false} />
<TextInput source="zipcode" helperText={false} />
<TextInput source="stateAbbr" helperText={false} />
<TextInput source="country" helperText={false} />
</div>
);
return (
<div className="flex flex-col gap-4">
<h6 className="text-lg font-semibold">Address</h6>
<TextInput source="address" helperText={false} labelInline />
<TextInput source="city" helperText={false} labelInline />
<TextInput source="zipcode" helperText={false} labelInline />
<TextInput source="stateAbbr" helperText={false} labelInline />
<TextInput source="country" helperText={false} labelInline />
</div>
);
};

const CompanyAdditionalInformationInputs = () => {
return (
<div className="flex flex-col gap-4">
<h6 className="text-lg font-semibold">Additional information</h6>
<TextInput source="description" multiline helperText={false} />
<ArrayInput source="context_links" helperText={false}>
<SimpleFormIterator disableReordering fullWidth getItemLabel={false}>
<TextInput
source=""
label={false}
helperText={false}
validate={isUrl}
/>
</SimpleFormIterator>
</ArrayInput>
</div>
);
return (
<div className="flex flex-col gap-4">
<h6 className="text-lg font-semibold">Additional information</h6>
<TextInput source="description" multiline helperText={false} />
<ArrayInput source="context_links" helperText={false}>
<SimpleFormIterator
disableReordering
fullWidth
getItemLabel={false}
>
<TextInput
source=""
label={false}
helperText={false}
placeholder="https://example.com"
validate={isUrl}
/>
</SimpleFormIterator>
</ArrayInput>
</div>
);
};

const CompanyAccountManagerInput = () => {
return (
<div className="flex flex-col gap-4">
<h6 className="text-lg font-semibold">Account manager</h6>
<ReferenceInput
source="sales_id"
reference="sales"
filter={{
"disabled@neq": true,
}}
>
<SelectInput
label="Account manager"
helperText={false}
optionText={saleOptionRenderer}
/>
</ReferenceInput>
</div>
);
return (
<div className="flex flex-col gap-4">
<h6 className="text-lg font-semibold">Account manager</h6>
<ReferenceInput
source="sales_id"
reference="sales"
filter={{ 'disabled@neq': true }}
>
<SelectInput
label="Account manager"
helperText={false}
optionText={saleOptionRenderer}
labelInline
/>
</ReferenceInput>
</div>
);
};

const saleOptionRenderer = (choice: Sale) =>
`${choice.first_name} ${choice.last_name}`;
`${choice.first_name} ${choice.last_name}`;
Loading