customer-module-frontend 1.0.1-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/.cursor/rules/context.md +306 -0
  2. package/.cursor/rules/guardrails.md +35 -0
  3. package/.env +1 -0
  4. package/.github/workflows/publish-to-npm-beta.yml +51 -0
  5. package/.github/workflows/publish-to-npm.yml +58 -0
  6. package/README.md +73 -0
  7. package/eslint.config.js +23 -0
  8. package/index.html +13 -0
  9. package/package.json +43 -0
  10. package/postcss-unwrap-layers.js +31 -0
  11. package/postcss.config.js +11 -0
  12. package/public/vite.svg +1 -0
  13. package/src/App.css +40 -0
  14. package/src/App.tsx +58 -0
  15. package/src/assets/accounts.svg +3 -0
  16. package/src/assets/at_the_rate.svg +10 -0
  17. package/src/assets/buildings.svg +3 -0
  18. package/src/assets/chat.svg +3 -0
  19. package/src/assets/close.svg +3 -0
  20. package/src/assets/contacts.svg +3 -0
  21. package/src/assets/conversation.svg +10 -0
  22. package/src/assets/customers.svg +10 -0
  23. package/src/assets/details.svg +3 -0
  24. package/src/assets/domain.svg +10 -0
  25. package/src/assets/edit.svg +15 -0
  26. package/src/assets/email.svg +3 -0
  27. package/src/assets/google.svg +8 -0
  28. package/src/assets/inbox.svg +0 -0
  29. package/src/assets/message.svg +3 -0
  30. package/src/assets/no-data.svg +9 -0
  31. package/src/assets/open_in_a_new_tab.svg +10 -0
  32. package/src/assets/phone.svg +3 -0
  33. package/src/assets/react.svg +1 -0
  34. package/src/assets/search.svg +3 -0
  35. package/src/assets/search_typing.svg +4 -0
  36. package/src/assets/sm_contacts.svg +3 -0
  37. package/src/assets/sm_inbox.svg +3 -0
  38. package/src/assets/sm_slider.svg +3 -0
  39. package/src/assets/status-resolved.svg +3 -0
  40. package/src/assets/status-snoozed.svg +4 -0
  41. package/src/assets/status_open.svg +1 -0
  42. package/src/components/AccountContacts/index.tsx +107 -0
  43. package/src/components/AccountDetails/index.tsx +102 -0
  44. package/src/components/AccountsConversation/index.tsx +75 -0
  45. package/src/components/Avatar/constants.tsx +45 -0
  46. package/src/components/Avatar/index.tsx +42 -0
  47. package/src/components/BreadcrumbsSection/index.tsx +16 -0
  48. package/src/components/Card/index.tsx +31 -0
  49. package/src/components/Card/types.ts +10 -0
  50. package/src/components/ContactConversation/Converation.tsx +14 -0
  51. package/src/components/ContactConversation/index.tsx +81 -0
  52. package/src/components/ContactDetails/index.tsx +111 -0
  53. package/src/components/Contacts/EditContact.tsx +213 -0
  54. package/src/components/Contacts/constants/index.tsx +24 -0
  55. package/src/components/Contacts/index.tsx +171 -0
  56. package/src/components/ConversationBox/constants.tsx +99 -0
  57. package/src/components/ConversationBox/index.tsx +147 -0
  58. package/src/components/ConversationBox/types.ts +20 -0
  59. package/src/components/CustomersLayout/index.tsx +20 -0
  60. package/src/components/DetailsCard/index.tsx +31 -0
  61. package/src/components/DetailsCard/types.ts +10 -0
  62. package/src/components/EmptyData/NoDataFound.tsx +31 -0
  63. package/src/components/Header/index.tsx +55 -0
  64. package/src/components/Icon/index.tsx +93 -0
  65. package/src/components/Icon/types.ts +13 -0
  66. package/src/components/Listing/AccountTable.tsx +47 -0
  67. package/src/components/Listing/ContactTable.tsx +76 -0
  68. package/src/components/RightPanel/AccountPanel.tsx +123 -0
  69. package/src/components/RightPanel/ContactPanel.tsx +142 -0
  70. package/src/components/RightPanel/index.tsx +167 -0
  71. package/src/components/Search/SearchDialog.tsx +150 -0
  72. package/src/components/TabsSection/index.tsx +49 -0
  73. package/src/constants/index.tsx +645 -0
  74. package/src/hooks/useBreadcrumb.tsx +93 -0
  75. package/src/index.css +315 -0
  76. package/src/main.tsx +14 -0
  77. package/src/pages/AccountDetail.tsx +68 -0
  78. package/src/pages/Accounts.tsx +12 -0
  79. package/src/pages/ContactDetail.tsx +55 -0
  80. package/src/pages/Contacts.tsx +12 -0
  81. package/src/stores/count.tsx +17 -0
  82. package/src/types/index.ts +0 -0
  83. package/tailwind.config.js +179 -0
  84. package/tsconfig.app.json +36 -0
  85. package/tsconfig.json +7 -0
  86. package/tsconfig.node.json +26 -0
  87. package/vite.config.ts +31 -0
@@ -0,0 +1,167 @@
1
+ import { useState } from 'react';
2
+ import Icon from '../Icon';
3
+ import { Tabs } from 'hiver-ui-kit-extended';
4
+ import ContactPanel from './ContactPanel';
5
+ import AccountPanel from './AccountPanel';
6
+ import type { ContactInfo, Conversation } from './ContactPanel';
7
+ import type { AccountInfo, Conversation as AccountConversation } from './AccountPanel';
8
+
9
+ // Sample data for the Contact Panel
10
+ const sampleContact: ContactInfo = {
11
+ name: 'John Acme',
12
+ email: 'john.acme@company.com',
13
+ phone: '+91 9890876545',
14
+ account: 'Google',
15
+ avatarColor: '#E37144',
16
+ };
17
+
18
+ const sampleConversations: Conversation[] = [
19
+ {
20
+ id: '1',
21
+ type: 'email',
22
+ status: 'open',
23
+ senderName: 'Carson Daily',
24
+ timestamp: 'Dec 12, 11:22 AM',
25
+ heading: 'Login issues',
26
+ messagePreview: 'I am having trouble with the app. It keeps cras...',
27
+ mailboxName: 'Finance',
28
+ assignedAgent: {
29
+ name: 'Zackary Smith',
30
+ },
31
+ },
32
+ {
33
+ id: '2',
34
+ type: 'chat',
35
+ status: 'closed',
36
+ senderName: 'Gigi Hadid',
37
+ timestamp: 'Jan 2, 09:56 AM',
38
+ messagePreview: 'I am unable to access key features. The loadin...',
39
+ mailboxName: 'Sales',
40
+ assignedAgent: {
41
+ name: 'Jolie Dale',
42
+ },
43
+ },
44
+ ];
45
+
46
+ // Sample data for the Account Panel
47
+ const sampleAccount: AccountInfo = {
48
+ name: 'Google',
49
+ domain: 'google.com',
50
+ contactCount: 122,
51
+ };
52
+
53
+ const sampleAccountConversations: AccountConversation[] = [
54
+ {
55
+ id: '1',
56
+ type: 'email',
57
+ status: 'open',
58
+ senderName: 'Carson Daily',
59
+ timestamp: 'Dec 12, 11:22 AM',
60
+ heading: 'Login issues',
61
+ messagePreview: 'I am having trouble with the app. It keeps cras...',
62
+ mailboxName: 'Finance',
63
+ assignedAgent: {
64
+ name: 'Zackary Smith',
65
+ },
66
+ },
67
+ {
68
+ id: '2',
69
+ type: 'email',
70
+ status: 'pending',
71
+ senderName: 'Lana Del Rey',
72
+ timestamp: 'Mar 7, 01:33 PM',
73
+ heading: "Can't connect to server",
74
+ messagePreview: 'I am having trouble with the app. It keeps cras...',
75
+ mailboxName: 'Finance',
76
+ assignedAgent: {
77
+ name: 'Zackary Smith',
78
+ },
79
+ },
80
+ {
81
+ id: '3',
82
+ type: 'chat',
83
+ status: 'closed',
84
+ senderName: 'Gigi Hadid',
85
+ timestamp: 'Jan 2, 09:56 AM',
86
+ messagePreview: 'I am unable to access key features. The loadin...',
87
+ mailboxName: 'Sales',
88
+ assignedAgent: {
89
+ name: 'Jolie Dale',
90
+ },
91
+ },
92
+ ];
93
+
94
+ const RightPanel = () => {
95
+ const [activeTab, setActiveTab] = useState<number>(1);
96
+
97
+ const tabItems = [
98
+ {
99
+ label: <Icon name="sm_slider" size={16} disabled color="#334155"/> as unknown as string,
100
+ content: <div>Slider</div>,
101
+ disabled: true,
102
+ },
103
+ {
104
+ label: <Icon name="sm_contacts" size={16} color="#334155" /> as unknown as string,
105
+ content: <ContactsTabs />,
106
+ },
107
+ {
108
+ label: <Icon name="sm_inbox" size={16} disabled color="#334155" /> as unknown as string,
109
+ content: <div>Inbox</div>,
110
+ disabled: true,
111
+ },
112
+ ];
113
+
114
+ return (
115
+ <div className="h-[100vh] bg-white [&_.p-tabview-panels]:p-0">
116
+ <Tabs
117
+ value={activeTab}
118
+ onTabChange={(e: { index: number }) => setActiveTab(e.index)}
119
+ items={tabItems}
120
+ />
121
+ </div>
122
+ );
123
+ };
124
+
125
+ export default RightPanel;
126
+
127
+ const ContactsTabs = () => {
128
+ const [activeTab, setActiveTab] = useState<number>(0);
129
+
130
+ const handleConversationClick = (conversationId: string) => {
131
+ console.log('Conversation clicked:', conversationId);
132
+ };
133
+
134
+ const tabItems = [
135
+ {
136
+ label: 'Contact',
137
+ content: (
138
+ <ContactPanel
139
+ contact={sampleContact}
140
+ conversations={sampleConversations}
141
+ onConversationClick={handleConversationClick}
142
+ />
143
+ ),
144
+ },
145
+ {
146
+ label: 'Account',
147
+ content: (
148
+ <AccountPanel
149
+ account={sampleAccount}
150
+ conversations={sampleAccountConversations}
151
+ onConversationClick={handleConversationClick}
152
+ />
153
+ ),
154
+ },
155
+ ];
156
+
157
+ return (
158
+ <div className="[&_.p-tabview-panels]:p-0">
159
+ <Tabs
160
+ value={activeTab}
161
+ onTabChange={(e: { index: number }) => setActiveTab(e.index)}
162
+ items={tabItems}
163
+ className="!h-[100px]"
164
+ />
165
+ </div>
166
+ );
167
+ };
@@ -0,0 +1,150 @@
1
+ import { useState } from "react";
2
+ import { Dialog, TextField } from "hiver-ui-kit-extended";
3
+ import BuildingsIcon from "../../assets/buildings.svg";
4
+ import Icon from "../Icon";
5
+ import searchIcon from "../../assets/search.svg";
6
+
7
+ // Dummy data array
8
+ const dummySearchResults = [
9
+ {
10
+ id: 1,
11
+ name: "John Doe",
12
+ email: "john.doe@example.com",
13
+ company: "Acme Corp",
14
+ lastContact: "2 days ago",
15
+ },
16
+ {
17
+ id: 2,
18
+ name: "Jane Smith",
19
+ email: "jane.smith@example.com",
20
+ company: "Tech Solutions",
21
+ lastContact: "1 week ago",
22
+ },
23
+ {
24
+ id: 3,
25
+ name: "Mike Johnson",
26
+ email: "mike.j@example.com",
27
+ company: "Global Industries",
28
+ lastContact: "3 days ago",
29
+ },
30
+ ];
31
+
32
+ interface SearchDialogProps {
33
+ open: boolean;
34
+ onClose: () => void;
35
+ }
36
+
37
+ const SearchDialog = ({ open, onClose }: SearchDialogProps) => {
38
+ const [searchQuery, setSearchQuery] = useState("");
39
+ const [searchResults, setSearchResults] = useState<typeof dummySearchResults>([]);
40
+
41
+ const handleSearchChange = (value: string) => {
42
+ setSearchQuery(value);
43
+
44
+ if (value.trim() === "") {
45
+ setSearchResults([]);
46
+ } else {
47
+ // Filter dummy data based on search query
48
+ const filtered = dummySearchResults.filter(
49
+ (item) =>
50
+ item.name.toLowerCase().includes(value.toLowerCase()) ||
51
+ item.email.toLowerCase().includes(value.toLowerCase()) ||
52
+ item.company.toLowerCase().includes(value.toLowerCase())
53
+ );
54
+ setSearchResults(filtered);
55
+ }
56
+ };
57
+
58
+ const StandardDialogContent = () => {
59
+ return (
60
+ <div className="flex items-center justify-center h-full">
61
+ <div className="cm:flex cm:flex-col cm:items-center cm:justify-center cm:gap-6">
62
+ <Icon name="search_typing" size={64} type="active" color="#0F172A" />
63
+ <div className="cm:text-label-small cm:text-slate-text-subtle">Start typing to search</div>
64
+ </div>
65
+ </div>
66
+ );
67
+ };
68
+
69
+ const SearchResults = () => {
70
+ return (
71
+ <div>
72
+ <div className="cm:text-slate-text-subtle cm:text-xs cm:font-medium cm:leading-[18px] cm:mb-2">
73
+ Accounts ({searchResults.length})
74
+ </div>
75
+
76
+ {searchResults.map((result) => (
77
+ <div key={result.id} className="cm:flex cm:py-1.5 cm:gap-1 cm:items-center">
78
+ <img src={BuildingsIcon} alt="Buildings" />
79
+ <div className="cm:text-slate-text-title cm:text-sm cm:font-medium cm:leading-5 cm:border-r cm:pr-1 cm:border-slate-border-light">
80
+ {result.company}
81
+ </div>
82
+
83
+
84
+ <div className="cm:text-slate-text-subtle cm:text-xs cm:font-normal cm:leading-[18px]">
85
+ {result.email}
86
+ </div>
87
+ </div>
88
+ ))}
89
+ </div>
90
+ );
91
+ };
92
+
93
+ const Search = (
94
+ <TextField
95
+ placeholder="Search..."
96
+ className="cm:w-full search-input-custom"
97
+ iconPosition="left"
98
+ value={searchQuery}
99
+ onChange={(e) => {
100
+ handleSearchChange(e.target.value);
101
+ }}
102
+ icon={searchIcon}
103
+ />
104
+ );
105
+
106
+ return (
107
+ <>
108
+ <style>{`
109
+ .search-input-custom,
110
+ .search-input-custom input,
111
+ .search-input-custom .p-inputtext,
112
+ .search-input-custom .omni-textfield-input {
113
+ border: none !important;
114
+ box-shadow: none !important;
115
+ outline: none !important;
116
+ }
117
+ .search-input-custom:hover,
118
+ .search-input-custom:focus,
119
+ .search-input-custom:focus-within,
120
+ .search-input-custom input:hover,
121
+ .search-input-custom input:focus,
122
+ .search-input-custom .p-inputtext:enabled:hover,
123
+ .search-input-custom .p-inputtext:enabled:focus,
124
+ .search-input-custom .omni-textfield-input:hover,
125
+ .search-input-custom .omni-textfield-input:focus {
126
+ border: none !important;
127
+ box-shadow: none !important;
128
+ outline: none !important;
129
+ }
130
+ `}</style>
131
+ <Dialog
132
+ open={open}
133
+ variant="standard"
134
+ onClose={onClose}
135
+ onBack={onClose}
136
+ maxWidth="sm"
137
+ title={Search}
138
+ className="cm:bg-slate-surface-white cm:h-[360px] cm:w-[460px]"
139
+ >
140
+ {searchResults.length === 0 ? (
141
+ <StandardDialogContent />
142
+ ) : (
143
+ <SearchResults />
144
+ )}
145
+ </Dialog>
146
+ </>
147
+ );
148
+ };
149
+
150
+ export default SearchDialog;
@@ -0,0 +1,49 @@
1
+ import { Tabs } from 'hiver-ui-kit-extended';
2
+ import { useLocation, useNavigate } from 'react-router-dom';
3
+ import Icon from '../Icon';
4
+
5
+ export default function TabsSection() {
6
+ const location = useLocation();
7
+ const navigate = useNavigate();
8
+
9
+ const paths = ['/accounts', '/contacts'];
10
+ const activeIndex = paths.findIndex((path) =>
11
+ location.pathname.startsWith(path)
12
+ );
13
+
14
+ const isActive = (index: number) => index === activeIndex;
15
+
16
+ const items = [
17
+ {
18
+ label: (
19
+ <div className="cm:flex cm:items-center cm:gap-2">
20
+ <Icon name="accounts" size={16} type="active" color={isActive(0) ? '#0F172A' : '#64758B'} />
21
+ Accounts
22
+ </div>
23
+ ) as unknown as string,
24
+ content: '',
25
+ path: '/accounts'
26
+ },
27
+ {
28
+ label: (
29
+ <div className="cm:flex cm:items-center cm:gap-2">
30
+ <Icon name="contacts" size={16} type="active" color={isActive(1) ? '#0F172A' : '#64758B'} />
31
+ Contacts
32
+ </div>
33
+ ) as unknown as string,
34
+ content: '',
35
+ path: '/contacts'
36
+ },
37
+ ];
38
+
39
+ const onTabChange = (e: any) => {
40
+ navigate(items[e.index].path);
41
+ };
42
+
43
+ return (
44
+ <div className="cm:mb-6">
45
+ <style>{`.p-tabview-panels { display: none; }`}</style>
46
+ <Tabs value={activeIndex} onTabChange={onTabChange} items={items} />
47
+ </div>
48
+ );
49
+ }