Skip to content

Commit

Permalink
feat(app-crm): contact modals (#4861)
Browse files Browse the repository at this point in the history
* feat: add contact card avatar

* feat: add single-element-form component

* feat: timezone enum

* feat: add style prop on `SingleElementForm`

* feat: add base contact status component

* fix: total count position

* feat: add ContactStatus component

* feat: add contact notes section

* fix: build error

* feat: add delete action

* feat: add defaultSorting and filters

* feat: text color improment

* fix: select bg

* feat: add avatar for select components

* feat: add company create modal

* feat: add sales owner selectbox

* fix: update sorter

* feat: updated form mode `optimistic`
  • Loading branch information
yildirayunlu authored Aug 25, 2023
1 parent c3d7488 commit 787a110
Show file tree
Hide file tree
Showing 22 changed files with 1,495 additions and 175 deletions.
15 changes: 13 additions & 2 deletions examples/app-crm/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,19 @@ const App: React.FC = () => {
/>
<Route
path="create"
element={<ContactCreatePage />}
/>
element={
<ContactCreatePage>
<Outlet />
</ContactCreatePage>
}
>
<Route
path="company-create"
element={
<CompanyCreatePage isOverModal />
}
/>
</Route>
</Route>
<Route
path="/quotes"
Expand Down
2 changes: 1 addition & 1 deletion examples/app-crm/src/components/contact/card/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export const ContactCard: React.FC<ContactCardProps> = ({
>
<Avatar
className={styles.avatar}
size={22}
size="small"
src={company.avatarUrl}
alt={company.name}
style={{ marginRight: 8, marginTop: -3 }}
Expand Down
89 changes: 89 additions & 0 deletions examples/app-crm/src/components/contact/comment/comment-form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import {
BaseKey,
HttpError,
useGetIdentity,
useInvalidate,
useParsed,
} from "@refinedev/core";
import { useForm } from "@refinedev/antd";
import { Avatar, Form, Input } from "antd";

import { ContactNote, User } from "../../../interfaces/graphql";

type FormValues = ContactNote & {
contactId: BaseKey;
};

export const ContactCommentForm = () => {
const { id: contactId } = useParsed();

const { data: me } = useGetIdentity<User>();

const { formProps, onFinish, form } = useForm<
ContactNote,
HttpError,
FormValues
>({
action: "create",
resource: "contactNotes",
queryOptions: {
enabled: false,
},
meta: {
operation: "contactNotes",
},
redirect: false,
mutationMode: "optimistic",
});

const handleOnFinish = async (values: ContactNote) => {
if (!contactId) {
return;
}

try {
await onFinish({
...values,
contactId,
});

form.resetFields();
} catch (error) {}
};

return (
<div
style={{
display: "flex",
alignItems: "center",
gap: "12px",
padding: "1rem",
}}
>
<Avatar
style={{
flexShrink: 0,
objectFit: "contain",
textTransform: "uppercase",
}}
size="small"
alt={me?.name}
src={me?.avatarUrl}
>
{me?.name.charAt(0)}
</Avatar>
<Form
{...formProps}
style={{ width: "100%" }}
onFinish={handleOnFinish}
>
<Form.Item name="note" noStyle>
<Input
placeholder="Write a comment"
style={{ backgroundColor: "#fff" }}
/>
</Form.Item>
</Form>
</div>
);
};
180 changes: 180 additions & 0 deletions examples/app-crm/src/components/contact/comment/comment-list.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
import {
HttpError,
useGetIdentity,
useList,
useParsed,
useInvalidate,
} from "@refinedev/core";
import { DeleteButton, useForm } from "@refinedev/antd";
import { Avatar, Form, Space, Typography, Input, Button } from "antd";
import dayjs from "dayjs";

import { Text } from "../../../components/text";
import { User, ContactNote } from "../../../interfaces/graphql";

const ContactCommentListItem = ({ item }: { item: ContactNote }) => {
const invalidate = useInvalidate();
const { formProps, setId, id, saveButtonProps } = useForm<
ContactNote,
HttpError,
ContactNote
>({
resource: "contactNotes",
action: "edit",
queryOptions: {
enabled: false,
},
mutationMode: "optimistic",
onMutationSuccess: () => {
setId(undefined);
invalidate({
invalidates: ["list"],
resource: "contactNotes",
});
},
});
const { data: me } = useGetIdentity<User>();

const isMe = me?.id === item.createdBy.id;

return (
<div style={{ display: "flex", gap: "12px" }}>
<Avatar
style={{
flexShrink: 0,
objectFit: "contain",
textTransform: "uppercase",
}}
size="small"
alt={item.createdBy.name}
src={item.createdBy.avatarUrl}
>
{item.createdBy.name.charAt(0)}
</Avatar>
<div
style={{
display: "flex",
flexDirection: "column",
gap: "8px",
width: "100%",
}}
>
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<Text style={{ fontWeight: 500 }}>
{item.createdBy.name}
</Text>
<Text size="xs" style={{ color: "#000000a6" }}>
{dayjs(item.createdAt).format("MMMM D, YYYY - h:ma")}
</Text>
</div>

{id ? (
<Form {...formProps} initialValues={{ note: item.note }}>
<Form.Item name="note" noStyle>
<Input.TextArea
autoFocus
style={{
backgroundColor: "#fff",
width: "100%",
}}
/>
</Form.Item>
</Form>
) : (
<Typography.Paragraph
style={{
background: "#fff",
borderRadius: "6px",
padding: "8px",
marginBottom: 0,
}}
ellipsis={{ rows: 3, expandable: true }}
>
{item.note}
</Typography.Paragraph>
)}

{isMe && !id && (
<Space size={16}>
<Typography.Link
style={{ color: "inherit", fontSize: "12px" }}
onClick={() => setId(item.id)}
>
Edit
</Typography.Link>
<DeleteButton
recordItemId={item.id}
meta={{ operation: "contactNote" }}
size="small"
type="link"
icon={null}
style={{
padding: 0,
fontSize: "12px",
color: "inherit",
}}
/>
</Space>
)}

{id && (
<Space>
<Button size="small" onClick={() => setId(undefined)}>
Cancel
</Button>
<Button
size="small"
type="primary"
{...saveButtonProps}
>
Save
</Button>
</Space>
)}
</div>
</div>
);
};

export const ContactCommentList = () => {
const { id } = useParsed();

const { data } = useList<ContactNote>({
resource: "contactNotes",
filters: [{ field: "contact.id", operator: "eq", value: id }],
sorters: [{ field: "createdAt", order: "desc" }],
pagination: {
mode: "off",
},
meta: {
fields: [
"id",
"note",
"createdAt",
{ createdBy: ["id", "name", "avatarUrl"] },
],
},
});

return (
<Space
size={16}
direction="vertical"
style={{
backgroundColor: "#FAFAFA",
padding: "1rem",
width: "100%",
}}
>
{data?.data?.map((item) => (
<ContactCommentListItem key={item.id} item={item} />
))}
</Space>
);
};
11 changes: 11 additions & 0 deletions examples/app-crm/src/components/contact/comment/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { ContactCommentForm } from "./comment-form";
import { ContactCommentList } from "./comment-list";

export const ContactComment = () => {
return (
<>
<ContactCommentForm />
<ContactCommentList />
</>
);
};
53 changes: 53 additions & 0 deletions examples/app-crm/src/components/contact/status/index.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
.container {
margin: 0;
padding: 0;
display: flex;
list-style-type: none;
width: 100%;
border-radius: 18px;
overflow: hidden;

.item {
display: flex;
align-items: center;
justify-content: center;
flex: 1;
height: 40px;
border-right: .5px solid #F0F2F5;

a {
color: #000;
font-size: 12px;
}
}

.arrow {
margin-left: .2rem;
}
}

.NEW, .CONTACTED, .INTERESTED .item {
background-color: #08979C;
a { color: #fff; }
}

.QUALIFIED, .NEGOTIATION .item {
background-color: #0958D9;
a { color: #fff; }
}

.WON .item {
background-color: #389E0D;
a { color: #fff; }
}

.UNQUALIFIED, .LOST, .CHURNED .item {
background-color: #CF1322;
a { color: #fff; }
}

.item.active ~ .item {
background-color: #fff;
a { color: #000; }
}

Loading

0 comments on commit 787a110

Please sign in to comment.