blixify-ui-web-mcp 0.1.3 → 0.1.19
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.
- package/lib/components/action/button/README.md +12 -11
- package/lib/components/action/button/button.stories.tsx +38 -27
- package/lib/components/action/buttonGroup/buttonGroup.stories.tsx +82 -16
- package/lib/components/action/iconButton/README.md +1 -0
- package/lib/components/action/iconButton/iconButton.stories.tsx +6 -12
- package/lib/components/action/radioList/radioList.stories.tsx +10 -16
- package/lib/components/action/slider/slider.stories.tsx +9 -15
- package/lib/components/action/textButton/textButton.stories.tsx +6 -12
- package/lib/components/action/toggle/toggle.stories.tsx +6 -12
- package/lib/components/advanced/collapse/collapse.stories.tsx +240 -24
- package/lib/components/advanced/infoWindow/infoWindow.stories.tsx +10 -16
- package/lib/components/advanced/popUp/README.md +33 -7
- package/lib/components/advanced/popUp/popUp.stories.tsx +9 -15
- package/lib/components/auth/bareSignIn/bareSignIn.stories.tsx +36 -16
- package/lib/components/auth/bareSignUp/bareSignUp.stories.tsx +7 -13
- package/lib/components/auth/signIn/signIn.stories.tsx +4 -10
- package/lib/components/auth/signUp/signUp.stories.tsx +4 -10
- package/lib/components/chart/areaChart/areaChart.stories.tsx +12 -18
- package/lib/components/chart/barChart/barChart.stories.tsx +12 -18
- package/lib/components/chart/boxPlotChart/boxPlotChart.stories.tsx +11 -17
- package/lib/components/chart/bubbleChart/bubbleChart.stories.tsx +11 -17
- package/lib/components/chart/card/card.stories.tsx +172 -38
- package/lib/components/chart/ganttChart/ganttChart.stories.tsx +10 -16
- package/lib/components/chart/heatmapChart/heatmapChart.stories.tsx +11 -17
- package/lib/components/chart/lineChart/lineChart.stories.tsx +8 -14
- package/lib/components/chart/pieChart/pieChart.stories.tsx +11 -17
- package/lib/components/chart/polarAreaChart/polarAreaChart.stories.tsx +11 -17
- package/lib/components/chart/radarChart/radarChart.stories.tsx +6 -12
- package/lib/components/chart/radialBar/radialChart.stories.tsx +4 -10
- package/lib/components/chart/rangeBarChart/rangeBarChart.stories.tsx +8 -14
- package/lib/components/chart/statsCard/statsCard.stories.tsx +12 -18
- package/lib/components/chart/treemapChart/treemapChart.stories.tsx +11 -17
- package/lib/components/chat/chatAnchor/README.md +7 -0
- package/lib/components/chat/chatAnchor/chatAnchor.stories.tsx +15 -21
- package/lib/components/chat/chatBase/README.md +103 -22
- package/lib/components/chat/chatBase/chatBase.stories.tsx +657 -57
- package/lib/components/chat/chatDashboard/README.md +17 -15
- package/lib/components/chat/chatDashboard/chatDashboard.stories.tsx +358 -46
- package/lib/components/data/dataGraph/dataGraph.stories.tsx +8 -14
- package/lib/components/data/dataReference/dataReference.stories.tsx +9 -15
- package/lib/components/data/dataTemplate/README.md +443 -129
- package/lib/components/data/dataTemplate/dataModule.stories.tsx +10 -15
- package/lib/components/data/dataTemplate/dataTemplate.stories.tsx +20 -34
- package/lib/components/data/dataWrapper/README.md +207 -84
- package/lib/components/data/dataWrapper/dataWrapper.consumer.stories.tsx +2125 -0
- package/lib/components/data/dataWrapper/dataWrapper.edit.stories.tsx +607 -0
- package/lib/components/data/dataWrapper/dataWrapper.utils.stories.tsx +576 -0
- package/lib/components/data/dataWrapper/dataWrapper.view.stories.tsx +1273 -0
- package/lib/components/data/flexFilter/flexFilter.stories.tsx +171 -0
- package/lib/components/data/queryForm/queryForm.stories.tsx +6 -12
- package/lib/components/data/readQuery/readQuery.stories.tsx +6 -11
- package/lib/components/data/readQueryHoc/readQueryHoc.stories.tsx +6 -12
- package/lib/components/data/writeQuery/README.md +21 -10
- package/lib/components/data/writeQuery/writeQuery.stories.tsx +6 -10
- package/lib/components/design/actionSection/actionSection.stories.tsx +10 -14
- package/lib/components/design/banner/banner.stories.tsx +6 -12
- package/lib/components/design/bannerAction/bannerAction.stories.tsx +100 -21
- package/lib/components/design/blogSection/blogSection.stories.tsx +6 -12
- package/lib/components/design/carouselSection/carouselSection.stories.tsx +6 -12
- package/lib/components/design/designList/designList.stories.tsx +6 -12
- package/lib/components/design/faq/faq.stories.tsx +53 -31
- package/lib/components/design/fileGrid/fileGrid.stories.tsx +10 -16
- package/lib/components/design/fileViewer/fileViewer.stories.tsx +6 -12
- package/lib/components/design/footerSection/footerSection.stories.tsx +6 -12
- package/lib/components/design/googleReview/googleReview.stories.tsx +6 -12
- package/lib/components/design/heroSection/heroSection.stories.tsx +10 -16
- package/lib/components/design/iconList/iconList.stories.tsx +6 -12
- package/lib/components/design/imageGallery/imageGallery.stories.tsx +6 -12
- package/lib/components/design/imageZoom/imageZoom.stories.tsx +6 -12
- package/lib/components/design/leftContent/leftContent.stories.tsx +6 -12
- package/lib/components/design/logoCloud/logoCloud.stories.tsx +6 -12
- package/lib/components/design/onboarding/onboarding.stories.tsx +8 -14
- package/lib/components/design/pricing/pricing.stories.tsx +6 -12
- package/lib/components/design/rightContent/rightContent.stories.tsx +6 -12
- package/lib/components/design/sectionList/sectionList.stories.tsx +6 -12
- package/lib/components/design/teams/teams.stories.tsx +6 -12
- package/lib/components/display/alert/alert.stories.tsx +8 -14
- package/lib/components/display/calendar/README.md +49 -0
- package/lib/components/display/calendar/calendar.stories.tsx +78 -35
- package/lib/components/display/clipboard/clipboard.stories.tsx +6 -12
- package/lib/components/display/detailList/detailList.stories.tsx +172 -48
- package/lib/components/display/drawer/README.md +44 -11
- package/lib/components/display/drawer/drawer.stories.tsx +71 -16
- package/lib/components/display/emptyState/emptyState.stories.tsx +47 -15
- package/lib/components/display/feeds/feeds.stories.tsx +6 -12
- package/lib/components/display/flexTable/README.md +11 -7
- package/lib/components/display/flexTable/flexTable.stories.tsx +318 -20
- package/lib/components/display/grid/README.md +29 -30
- package/lib/components/display/grid/grid.stories.tsx +16 -23
- package/lib/components/display/kanban/kanban.stories.tsx +17 -23
- package/lib/components/display/list/README.md +30 -29
- package/lib/components/display/list/list.stories.tsx +11 -17
- package/lib/components/display/loading/loading.stories.tsx +7 -12
- package/lib/components/display/mapView/mapView.stories.tsx +9 -15
- package/lib/components/display/modal/modal.stories.tsx +6 -13
- package/lib/components/display/newCalendar/README.md +163 -0
- package/lib/components/display/newCalendar/newCalendar.stories.tsx +292 -0
- package/lib/components/display/newFeeds/README.md +53 -0
- package/lib/components/display/newFeeds/newFeeds.stories.tsx +104 -0
- package/lib/components/display/newKanban/README.md +25 -0
- package/lib/components/display/newKanban/newKanban.stories.tsx +131 -0
- package/lib/components/display/newList/README.md +30 -0
- package/lib/components/display/newList/newList.stories.tsx +231 -0
- package/lib/components/display/newPagination/README.md +15 -0
- package/lib/components/display/newTable/README.md +121 -0
- package/lib/components/display/newTable/newTable.stories.tsx +551 -0
- package/lib/components/display/notification/notification.stories.tsx +6 -12
- package/lib/components/display/progress/progress.stories.tsx +7 -12
- package/lib/components/display/stepper/README.md +4 -0
- package/lib/components/display/stepper/stepper.stories.tsx +70 -23
- package/lib/components/display/table/README.md +38 -37
- package/lib/components/display/table/table.stories.tsx +34 -36
- package/lib/components/display/tag/tag.stories.tsx +34 -40
- package/lib/components/input/address/address.stories.tsx +12 -18
- package/lib/components/input/canvas/canvas.stories.tsx +12 -18
- package/lib/components/input/checkbox/checkbox.stories.tsx +7 -13
- package/lib/components/input/datePicker/datePicker.stories.tsx +41 -11
- package/lib/components/input/form/form.stories.tsx +11 -17
- package/lib/components/input/markdown/README.md +80 -2
- package/lib/components/input/markdown/markdown.stories.tsx +83 -32
- package/lib/components/input/monthYearPicker/monthYearPicker.stories.tsx +52 -24
- package/lib/components/input/netPromoterScore/netPromoterScore.stories.tsx +6 -12
- package/lib/components/input/rating/rating.stories.tsx +6 -12
- package/lib/components/input/select/README.md +31 -29
- package/lib/components/input/select/select.stories.tsx +33 -39
- package/lib/components/input/signature/signature.stories.tsx +12 -18
- package/lib/components/input/textArea/textArea.stories.tsx +6 -12
- package/lib/components/input/textInput/textinput.stories.tsx +14 -20
- package/lib/components/input/uploadInput/uploadInput.stories.tsx +143 -19
- package/lib/components/navigation/bars/README.md +27 -0
- package/lib/components/navigation/bars/bars.stories.tsx +56 -19
- package/lib/components/navigation/bottomTab/bottomTab.stories.tsx +7 -12
- package/lib/components/navigation/breadcrumb/breadcrumb.stories.tsx +8 -14
- package/lib/components/navigation/header/header.stories.tsx +33 -21
- package/lib/components/navigation/leftNav/leftNav.stories.tsx +10 -16
- package/lib/components/navigation/tabs/tabs.stories.tsx +10 -16
- package/lib/components/structure/column/column.stories.tsx +10 -15
- package/lib/components/structure/container/container.stories.tsx +8 -13
- package/lib/components/structure/link/link.stories.tsx +11 -17
- package/lib/components/structure/text/text.stories.tsx +12 -17
- package/lib/components/template/authPage/authPage.stories.tsx +6 -5
- package/lib/components/template/calendarView/calendarView.stories.tsx +726 -0
- package/lib/components/template/chatDashboard/chatDashboard.stories.tsx +497 -0
- package/lib/components/template/landingPage/landingPage.stories.tsx +10 -7
- package/lib/components/template/mapLayout/mapLayout.stories.tsx +519 -0
- package/lib/components/template/productListing/productListing.stories.tsx +7 -13
- package/lib/components/template/productOverview/productOverview.stories.tsx +5 -11
- package/lib/components/template/shoppingCart/shoppingCart.stories.tsx +6 -12
- package/lib/components/template/userHomePage/userHomePage.stories.tsx +384 -524
- package/lib/components/template/userRankingDashboard/userRankingDashboard.stories.tsx +145 -75
- package/lib/mcp/tools/componentsRoot.d.ts +2 -0
- package/lib/mcp/tools/componentsRoot.d.ts.map +1 -0
- package/lib/mcp/tools/componentsRoot.js +59 -0
- package/lib/mcp/tools/componentsRoot.js.map +1 -0
- package/lib/mcp/tools/getBackendComponent.d.ts.map +1 -1
- package/lib/mcp/tools/getBackendComponent.js +2 -5
- package/lib/mcp/tools/getBackendComponent.js.map +1 -1
- package/lib/mcp/tools/getComponent.d.ts.map +1 -1
- package/lib/mcp/tools/getComponent.js +2 -5
- package/lib/mcp/tools/getComponent.js.map +1 -1
- package/lib/mcp/tools/listComponents.d.ts.map +1 -1
- package/lib/mcp/tools/listComponents.js +15 -10
- package/lib/mcp/tools/listComponents.js.map +1 -1
- package/lib/mcp/tools/suggestTemplate.d.ts.map +1 -1
- package/lib/mcp/tools/suggestTemplate.js +107 -21
- package/lib/mcp/tools/suggestTemplate.js.map +1 -1
- package/package.json +1 -1
- package/lib/components/data/dataWrapper/dataWrapper.stories.tsx +0 -831
|
@@ -74,20 +74,22 @@ const headerElement = (
|
|
|
74
74
|
|
|
75
75
|
##### Optional props
|
|
76
76
|
|
|
77
|
-
| Name | Type | Default | Description
|
|
78
|
-
| ----------------------- | -------------------------------------- | ---------- |
|
|
79
|
-
| `mobileSelectedChat` | `boolean` | `false` | When `true`, hides the conversation list and shows the chat panel on mobile. Set to `false` to go back to the list.
|
|
80
|
-
| `
|
|
81
|
-
| `
|
|
82
|
-
| `
|
|
83
|
-
| `
|
|
84
|
-
| `
|
|
85
|
-
| `
|
|
86
|
-
| `
|
|
87
|
-
| `
|
|
88
|
-
| `
|
|
89
|
-
| `
|
|
90
|
-
| `
|
|
77
|
+
| Name | Type | Default | Description |
|
|
78
|
+
| ----------------------- | -------------------------------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
|
79
|
+
| `mobileSelectedChat` | `boolean` | `false` | When `true`, hides the conversation list and shows the chat panel on mobile. Set to `false` to go back to the list. |
|
|
80
|
+
| `disableMessageInput` | `boolean` | `false` | When `true`, message input is disabled. |
|
|
81
|
+
| `searchMessage` | `string` | — | Current search input value. Pass a filtered conversation to `selectedConversation` to show results. |
|
|
82
|
+
| `headerElement` | `ReactElement` | — | Replaces the default `ChatBase` header. Use this to show the other user's name and a mobile back button. |
|
|
83
|
+
| `bodyElement` | `ReactElement` | — | Replaces the `ChatBase` message list. Useful for showing a loading spinner while fetching messages. |
|
|
84
|
+
| `className` | `string` | — | Tailwind classes for the conversation list panel container |
|
|
85
|
+
| `sizeClassName` | `string` | `h-[75vh]` | Tailwind classes controlling the height/width of the conversation list panel |
|
|
86
|
+
| `chatBaseClassName` | `string` | — | Tailwind classes for the `ChatBase` container |
|
|
87
|
+
| `chatBaseSizeClassName` | `string` | — | Tailwind classes controlling the height/width of the `ChatBase` panel |
|
|
88
|
+
| `onSendMessage` | `(conversation: Conversation) => void` | — | Called with the updated conversation when a message is sent |
|
|
89
|
+
| `onChangeMessage` | `(event: any) => void` | — | Called on every keystroke in the message input |
|
|
90
|
+
| `onSearch` | `(searchMessage: string) => void` | — | Called when the search form is submitted inside `ChatBase` |
|
|
91
|
+
| `onChangeSearch` | `(event: any) => void` | — | Called on every keystroke in the search input inside `ChatBase` |
|
|
92
|
+
| `additionalAction` | `ChatBaseAction[]` | — | Extra items appended to the `⋮` actions menu in the chat panel. Each item requires `text` and `onClick`, with an optional `icon`. |
|
|
91
93
|
|
|
92
94
|
##### Conversation list behaviour
|
|
93
95
|
|
|
@@ -113,7 +115,7 @@ Each item in `conversationList` renders the other user's avatar and name (the me
|
|
|
113
115
|
|
|
114
116
|
| Name | Type | Description |
|
|
115
117
|
| -------------- | ------------------- | ----------------------------------------------------------------- |
|
|
116
|
-
| `sender` | `User` | The user who sent the message
|
|
118
|
+
| `sender` | `User` | The user who sent the message. |
|
|
117
119
|
| `messageBody` | `string \| FileObj` | Text content or a file object for image/video messages |
|
|
118
120
|
| `reactElement` | `ReactElement` | Optional — replaces `messageBody` rendering with a custom element |
|
|
119
121
|
| `createdAt` | `Date` | Timestamp |
|
|
@@ -1,31 +1,41 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
ChevronLeftIcon,
|
|
3
|
+
PencilSquareIcon,
|
|
4
|
+
TrashIcon,
|
|
5
|
+
} from "@heroicons/react/24/outline";
|
|
6
|
+
import dayjs from "../../dayjs";
|
|
4
7
|
import React, { useEffect, useState } from "react";
|
|
5
|
-
import {
|
|
8
|
+
import { v4 as uuidv4 } from "uuid";
|
|
9
|
+
import { ChatDashboard as ChatDashboardImpl } from ".";
|
|
6
10
|
import { StorySection } from "../../storyUtils";
|
|
7
11
|
import { IconButton } from "../../action/iconButton";
|
|
8
12
|
import { Loading } from "../../display/loading";
|
|
9
|
-
import { Conversation } from "../chatBase";
|
|
13
|
+
import { ChatBaseAction, Conversation } from "../chatBase";
|
|
10
14
|
import { conversationList as seedConvoList, currentUser } from "../chatUtils";
|
|
11
|
-
import
|
|
15
|
+
import { Button } from "../../action/button";
|
|
12
16
|
|
|
13
|
-
const
|
|
17
|
+
const meta = { title: "Chat/Chat Dashboard" };
|
|
18
|
+
export default meta;
|
|
14
19
|
|
|
15
|
-
stories.addParameters({
|
|
16
|
-
readme: {
|
|
17
|
-
content: README,
|
|
18
|
-
},
|
|
19
|
-
});
|
|
20
20
|
|
|
21
21
|
const sortByLatest = (list: Conversation[]) =>
|
|
22
22
|
[...list].sort((a, b) =>
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
)
|
|
23
|
+
dayjs(b.messageList[b.messageList.length - 1].createdAt).diff(
|
|
24
|
+
dayjs(a.messageList[a.messageList.length - 1].createdAt),
|
|
25
|
+
),
|
|
26
26
|
);
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
// INFO: demo statuses for renderConversationMeta / renderHeaderTags
|
|
29
|
+
const DEMO_STATUSES = ["active", "waiting", "closed", "assigned"];
|
|
30
|
+
const DEMO_BADGE_COLORS: Record<string, string> = {
|
|
31
|
+
active: "bg-green-100 text-green-700",
|
|
32
|
+
waiting: "bg-yellow-100 text-yellow-700",
|
|
33
|
+
closed: "bg-gray-100 text-gray-500",
|
|
34
|
+
assigned: "bg-blue-100 text-blue-700",
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const ChatDashboard = () => {
|
|
38
|
+
// INFO: Section 1 — Base chat state
|
|
29
39
|
const [message, setMessage] = useState("");
|
|
30
40
|
const [search, setSearch] = useState("");
|
|
31
41
|
const [isLoading, setIsLoading] = useState(false);
|
|
@@ -38,11 +48,99 @@ stories.add("Chat Dashboard", () => {
|
|
|
38
48
|
members: [],
|
|
39
49
|
messageList: [],
|
|
40
50
|
});
|
|
51
|
+
const [file, setFile] = useState<File | any>(undefined);
|
|
52
|
+
|
|
53
|
+
// INFO: Section 2 — Meta & Tags state
|
|
54
|
+
const [metaConvoList, setMetaConvoList] = useState<Conversation[]>([]);
|
|
55
|
+
const [metaConvo, setMetaConvo] = useState<Conversation>({
|
|
56
|
+
id: "",
|
|
57
|
+
members: [],
|
|
58
|
+
messageList: [],
|
|
59
|
+
});
|
|
60
|
+
const [metaMessage, setMetaMessage] = useState("");
|
|
61
|
+
|
|
62
|
+
// INFO: Section 3 — Pagination state
|
|
63
|
+
const [paginationConvoList, setPaginationConvoList] = useState<
|
|
64
|
+
Conversation[]
|
|
65
|
+
>([]);
|
|
66
|
+
const [paginationConvo, setPaginationConvo] = useState<Conversation>({
|
|
67
|
+
id: "",
|
|
68
|
+
members: [],
|
|
69
|
+
messageList: [],
|
|
70
|
+
});
|
|
71
|
+
const [paginationMessage, setPaginationMessage] = useState("");
|
|
72
|
+
const [page, setPage] = useState(1);
|
|
73
|
+
const [loadingConversations, setLoadingConversations] = useState(false);
|
|
74
|
+
const [loadingMessages, setLoadingMessages] = useState(false);
|
|
75
|
+
const [msgPage, setMsgPage] = useState(1);
|
|
76
|
+
|
|
77
|
+
// INFO: pageNum 0 generates 15 contacts to ensure the list overflows and is scrollable
|
|
78
|
+
const generateConversations = (pageNum: number): Conversation[] => {
|
|
79
|
+
const count = pageNum === 1 ? 15 : 5;
|
|
80
|
+
return Array.from({ length: count }, (_, i) => {
|
|
81
|
+
const idx = (pageNum - 1) * 5 + i;
|
|
82
|
+
const otherUser = {
|
|
83
|
+
id: `user-${idx}`,
|
|
84
|
+
name: `Contact ${idx + 1}`,
|
|
85
|
+
imageUrl: `https://ui-avatars.com/api/?name=C${idx + 1}&background=6366f1&color=fff`,
|
|
86
|
+
};
|
|
87
|
+
return {
|
|
88
|
+
id: uuidv4(),
|
|
89
|
+
members: [currentUser, otherUser],
|
|
90
|
+
messageList: Array.from({ length: 10 }, (_, j) => ({
|
|
91
|
+
sender: j % 2 === 0 ? otherUser : currentUser,
|
|
92
|
+
messageBody: `Message ${j + 1} from page ${pageNum}`,
|
|
93
|
+
createdAt: dayjs()
|
|
94
|
+
.subtract(10 - j, "minutes")
|
|
95
|
+
.toDate(),
|
|
96
|
+
})),
|
|
97
|
+
};
|
|
98
|
+
});
|
|
99
|
+
};
|
|
41
100
|
|
|
42
101
|
useEffect(() => {
|
|
43
|
-
|
|
102
|
+
// INFO: inject demo images of varying aspect ratios to exercise the bubble size cap
|
|
103
|
+
const demoImages = [
|
|
104
|
+
{ id: 1015, w: 1600, h: 900, label: "Landscape (16:9)" },
|
|
105
|
+
{ id: 1027, w: 900, h: 1600, label: "Portrait (9:16)" },
|
|
106
|
+
{ id: 237, w: 1200, h: 1200, label: "Square (1:1)" },
|
|
107
|
+
];
|
|
108
|
+
const withImages = seedConvoList.map((convo, idx) =>
|
|
109
|
+
idx === 0
|
|
110
|
+
? {
|
|
111
|
+
...convo,
|
|
112
|
+
messageList: [
|
|
113
|
+
...convo.messageList,
|
|
114
|
+
...demoImages.map((img) => ({
|
|
115
|
+
sender: convo.members.find((m) => m.id !== currentUser.id)!,
|
|
116
|
+
messageBody: {
|
|
117
|
+
fileName: `https://picsum.photos/id/${img.id}/${img.w}/${img.h}`,
|
|
118
|
+
token: img.label,
|
|
119
|
+
type: "image/jpeg",
|
|
120
|
+
},
|
|
121
|
+
createdAt: dayjs().subtract(demoImages.length - img.id, "minutes").toDate(),
|
|
122
|
+
})),
|
|
123
|
+
{
|
|
124
|
+
sender: convo.members.find((m) => m.id !== currentUser.id)!,
|
|
125
|
+
messageBody: {
|
|
126
|
+
fileName: "https://www.w3schools.com/html/mov_bbb.mp4",
|
|
127
|
+
token: "Sample video",
|
|
128
|
+
type: "video/mp4",
|
|
129
|
+
},
|
|
130
|
+
createdAt: dayjs().toDate(),
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
}
|
|
134
|
+
: convo,
|
|
135
|
+
);
|
|
136
|
+
const sorted = sortByLatest(withImages);
|
|
44
137
|
setConversationList(sorted);
|
|
45
138
|
setConversation(sorted[0]);
|
|
139
|
+
setMetaConvoList(sorted);
|
|
140
|
+
setMetaConvo(sorted[0]);
|
|
141
|
+
const initial = generateConversations(1);
|
|
142
|
+
setPaginationConvoList(initial);
|
|
143
|
+
setPaginationConvo(initial[0]);
|
|
46
144
|
}, []);
|
|
47
145
|
|
|
48
146
|
const handleSelectConversation = (id: string) => {
|
|
@@ -58,10 +156,11 @@ stories.add("Chat Dashboard", () => {
|
|
|
58
156
|
const handleSendMessage = (updated: Conversation) => {
|
|
59
157
|
setConversation(updated);
|
|
60
158
|
setMessage("");
|
|
61
|
-
|
|
62
|
-
|
|
159
|
+
setConversationList(
|
|
160
|
+
sortByLatest(
|
|
161
|
+
conversationList.map((c) => (c.id === updated.id ? updated : c)),
|
|
162
|
+
),
|
|
63
163
|
);
|
|
64
|
-
setConversationList(sortByLatest(updatedList));
|
|
65
164
|
};
|
|
66
165
|
|
|
67
166
|
const handleSearch = (searchMessage: string) => {
|
|
@@ -74,58 +173,271 @@ stories.add("Chat Dashboard", () => {
|
|
|
74
173
|
messageList: conversation.messageList.filter(
|
|
75
174
|
(m) =>
|
|
76
175
|
typeof m.messageBody === "string" &&
|
|
77
|
-
m.messageBody.toLowerCase().includes(searchMessage.toLowerCase())
|
|
176
|
+
m.messageBody.toLowerCase().includes(searchMessage.toLowerCase()),
|
|
78
177
|
),
|
|
79
178
|
});
|
|
80
179
|
}
|
|
81
180
|
};
|
|
82
181
|
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
182
|
+
const handleSendUpload = (conv: Conversation, uploadedFile: File) => {
|
|
183
|
+
const fileUrl = URL.createObjectURL(uploadedFile);
|
|
184
|
+
const updated: Conversation = {
|
|
185
|
+
...conv,
|
|
186
|
+
messageList: [
|
|
187
|
+
...conv.messageList,
|
|
188
|
+
{
|
|
189
|
+
sender: currentUser,
|
|
190
|
+
messageBody: {
|
|
191
|
+
fileName: fileUrl,
|
|
192
|
+
token: uuidv4(),
|
|
193
|
+
type: uploadedFile.type,
|
|
194
|
+
},
|
|
195
|
+
createdAt: dayjs().toDate(),
|
|
196
|
+
},
|
|
197
|
+
],
|
|
198
|
+
};
|
|
199
|
+
setConversation(updated);
|
|
200
|
+
setFile(undefined);
|
|
201
|
+
setConversationList(
|
|
202
|
+
sortByLatest(
|
|
203
|
+
conversationList.map((c) => (c.id === updated.id ? updated : c)),
|
|
204
|
+
),
|
|
205
|
+
);
|
|
206
|
+
};
|
|
96
207
|
|
|
97
|
-
const
|
|
98
|
-
<div className="w-full h-full flex items-center justify-center">
|
|
99
|
-
<Loading />
|
|
100
|
-
</div>
|
|
101
|
-
) : undefined;
|
|
208
|
+
const otherUser = conversation.members.find((m) => m.id !== currentUser.id);
|
|
102
209
|
|
|
103
210
|
return (
|
|
104
211
|
<>
|
|
212
|
+
{/* INFO: Section 1 — Base chat with file upload, search, actions */}
|
|
105
213
|
<StorySection
|
|
106
|
-
title="Chat
|
|
107
|
-
description="
|
|
214
|
+
title="Base Chat"
|
|
215
|
+
description="Two-panel layout with conversation list, file upload, search, and actions. Mobile toggle via mobileSelectedChat."
|
|
108
216
|
>
|
|
109
217
|
<div className="w-full">
|
|
110
|
-
<
|
|
218
|
+
<ChatDashboardImpl
|
|
111
219
|
value={message}
|
|
112
220
|
searchMessage={search}
|
|
113
221
|
currentUser={currentUser}
|
|
114
222
|
selectedConversation={filteredConversation ?? conversation}
|
|
115
223
|
conversationList={conversationList}
|
|
116
224
|
mobileSelectedChat={mobileSelectedChat}
|
|
117
|
-
sizeClassName="w-
|
|
225
|
+
sizeClassName="w-96 h-[60vh]"
|
|
118
226
|
chatBaseSizeClassName="w-full h-[60vh]"
|
|
119
|
-
headerElement={
|
|
120
|
-
|
|
227
|
+
headerElement={
|
|
228
|
+
<div className="w-full flex items-center h-12 text-white bg-primary-500">
|
|
229
|
+
<IconButton
|
|
230
|
+
icon={<ChevronLeftIcon className="w-6 h-6" />}
|
|
231
|
+
background="bg-transparent"
|
|
232
|
+
onClick={() => setMobileSelectedChat(false)}
|
|
233
|
+
className={`${!mobileSelectedChat ? "hidden sm:flex" : ""} sm:hidden`}
|
|
234
|
+
/>
|
|
235
|
+
<p className="ml-2 sm:ml-4 font-medium">
|
|
236
|
+
{otherUser?.name ?? "Chat"}
|
|
237
|
+
</p>
|
|
238
|
+
</div>
|
|
239
|
+
}
|
|
240
|
+
bodyElement={
|
|
241
|
+
isLoading ? (
|
|
242
|
+
<div className="w-full h-full flex items-center justify-center">
|
|
243
|
+
<Loading />
|
|
244
|
+
</div>
|
|
245
|
+
) : undefined
|
|
246
|
+
}
|
|
247
|
+
fileUpload={{
|
|
248
|
+
allowFileUpload: true,
|
|
249
|
+
file,
|
|
250
|
+
acceptFileType: ".jpg,.jpeg,.png,.mp4,.webm",
|
|
251
|
+
onChangeUpload: (e) => {
|
|
252
|
+
if (e?.target?.files?.length > 0) setFile(e.target.files[0]);
|
|
253
|
+
else setFile(undefined);
|
|
254
|
+
},
|
|
255
|
+
onSendUpload: handleSendUpload,
|
|
256
|
+
}}
|
|
257
|
+
leftPanelHeaderElement={
|
|
258
|
+
<div className="p-4">
|
|
259
|
+
<Button
|
|
260
|
+
type="normal"
|
|
261
|
+
size="small"
|
|
262
|
+
text="New Chat"
|
|
263
|
+
icon={<PencilSquareIcon className="w-4 h-4" />}
|
|
264
|
+
onClick={() => alert("New Chat clicked")}
|
|
265
|
+
className="w-full"
|
|
266
|
+
/>
|
|
267
|
+
</div>
|
|
268
|
+
}
|
|
121
269
|
onChangeMessage={(e) => setMessage(e.target.value)}
|
|
122
270
|
onSendMessage={handleSendMessage}
|
|
123
271
|
onChangeSearch={(e) => setSearch(e.target.value)}
|
|
124
272
|
onSearch={handleSearch}
|
|
125
273
|
handleSelectedConversation={handleSelectConversation}
|
|
274
|
+
additionalAction={
|
|
275
|
+
[
|
|
276
|
+
{
|
|
277
|
+
text: "Clear Chat",
|
|
278
|
+
onClick: () =>
|
|
279
|
+
setConversation((prev) => ({ ...prev, messageList: [] })),
|
|
280
|
+
icon: <TrashIcon className="w-3 h-3" />,
|
|
281
|
+
},
|
|
282
|
+
] as ChatBaseAction[]
|
|
283
|
+
}
|
|
284
|
+
/>
|
|
285
|
+
</div>
|
|
286
|
+
</StorySection>
|
|
287
|
+
|
|
288
|
+
{/* INFO: Section 2 — renderConversationMeta + renderHeaderTags */}
|
|
289
|
+
<StorySection
|
|
290
|
+
title="Meta Badges & Header Tags"
|
|
291
|
+
description="renderConversationMeta shows status badges and 'Needs Reply' on left panel items. renderHeaderTags shows tags in the chat header."
|
|
292
|
+
>
|
|
293
|
+
<div className="w-full">
|
|
294
|
+
<ChatDashboardImpl
|
|
295
|
+
value={metaMessage}
|
|
296
|
+
currentUser={currentUser}
|
|
297
|
+
selectedConversation={metaConvo}
|
|
298
|
+
conversationList={metaConvoList}
|
|
299
|
+
sizeClassName="w-96 h-[60vh]"
|
|
300
|
+
chatBaseSizeClassName="w-full h-[60vh]"
|
|
301
|
+
headerElement={
|
|
302
|
+
<div className="w-full flex items-center h-12 px-4 text-white bg-primary-500">
|
|
303
|
+
<p className="font-medium">
|
|
304
|
+
{metaConvo.members.find((m) => m.id !== currentUser.id)
|
|
305
|
+
?.name ?? "Chat"}
|
|
306
|
+
</p>
|
|
307
|
+
</div>
|
|
308
|
+
}
|
|
309
|
+
renderConversationMeta={(convo) => {
|
|
310
|
+
const status =
|
|
311
|
+
DEMO_STATUSES[
|
|
312
|
+
Math.abs(convo.id.charCodeAt(0)) % DEMO_STATUSES.length
|
|
313
|
+
];
|
|
314
|
+
const needsReply = convo.id.charCodeAt(0) % 2 === 0;
|
|
315
|
+
return (
|
|
316
|
+
<div className="flex gap-1 mt-1 flex-wrap">
|
|
317
|
+
<span
|
|
318
|
+
className={`text-[10px] px-1.5 py-0.5 rounded ${DEMO_BADGE_COLORS[status]}`}
|
|
319
|
+
>
|
|
320
|
+
{status}
|
|
321
|
+
</span>
|
|
322
|
+
{needsReply && (
|
|
323
|
+
<span className="text-[10px] px-1.5 py-0.5 rounded bg-orange-100 text-orange-700">
|
|
324
|
+
Needs Reply
|
|
325
|
+
</span>
|
|
326
|
+
)}
|
|
327
|
+
</div>
|
|
328
|
+
);
|
|
329
|
+
}}
|
|
330
|
+
renderHeaderTags={(convo) => {
|
|
331
|
+
const status =
|
|
332
|
+
DEMO_STATUSES[
|
|
333
|
+
Math.abs(convo.id.charCodeAt(0)) % DEMO_STATUSES.length
|
|
334
|
+
];
|
|
335
|
+
return (
|
|
336
|
+
<div className="flex gap-1">
|
|
337
|
+
<span className="text-[10px] px-1.5 py-0.5 rounded bg-white/20 text-white">
|
|
338
|
+
{status}
|
|
339
|
+
</span>
|
|
340
|
+
<span className="text-[10px] px-1.5 py-0.5 rounded bg-white/20 text-white">
|
|
341
|
+
whatsapp
|
|
342
|
+
</span>
|
|
343
|
+
</div>
|
|
344
|
+
);
|
|
345
|
+
}}
|
|
346
|
+
onChangeMessage={(e) => setMetaMessage(e.target.value)}
|
|
347
|
+
onSendMessage={(updated) => {
|
|
348
|
+
setMetaConvo(updated);
|
|
349
|
+
setMetaMessage("");
|
|
350
|
+
setMetaConvoList((prev) =>
|
|
351
|
+
sortByLatest(
|
|
352
|
+
prev.map((c) => (c.id === updated.id ? updated : c)),
|
|
353
|
+
),
|
|
354
|
+
);
|
|
355
|
+
}}
|
|
356
|
+
handleSelectedConversation={(id) => {
|
|
357
|
+
const found = metaConvoList.find((c) => c.id === id);
|
|
358
|
+
if (found) setMetaConvo(found);
|
|
359
|
+
}}
|
|
360
|
+
/>
|
|
361
|
+
</div>
|
|
362
|
+
</StorySection>
|
|
363
|
+
|
|
364
|
+
{/* INFO: Section 3 — Pagination scroll callbacks */}
|
|
365
|
+
<StorySection
|
|
366
|
+
title="Pagination (Infinite Scroll)"
|
|
367
|
+
description="onConversationListScrollEnd loads more contacts with a spinner at the bottom. onMessageListScrollTop prepends older messages with a spinner at the top. Scroll to see both effects."
|
|
368
|
+
>
|
|
369
|
+
<div className="w-full">
|
|
370
|
+
<ChatDashboardImpl
|
|
371
|
+
value={paginationMessage}
|
|
372
|
+
currentUser={currentUser}
|
|
373
|
+
selectedConversation={paginationConvo}
|
|
374
|
+
conversationList={paginationConvoList}
|
|
375
|
+
isLoadingConversations={loadingConversations}
|
|
376
|
+
isLoadingMessages={loadingMessages}
|
|
377
|
+
sizeClassName="w-96 h-[60vh]"
|
|
378
|
+
chatBaseSizeClassName="w-full h-[60vh]"
|
|
379
|
+
headerElement={
|
|
380
|
+
<div className="w-full flex items-center h-12 px-4 text-white bg-primary-500">
|
|
381
|
+
<p className="font-medium">
|
|
382
|
+
{paginationConvo.members.find(
|
|
383
|
+
(m) => m.id !== currentUser.id,
|
|
384
|
+
)?.name ?? "Chat"}
|
|
385
|
+
</p>
|
|
386
|
+
</div>
|
|
387
|
+
}
|
|
388
|
+
onConversationListScrollEnd={() => {
|
|
389
|
+
setLoadingConversations(true);
|
|
390
|
+
const nextPage = page + 1;
|
|
391
|
+
setTimeout(() => {
|
|
392
|
+
const more = generateConversations(nextPage);
|
|
393
|
+
setPaginationConvoList((prev) => [...prev, ...more]);
|
|
394
|
+
setPage(nextPage);
|
|
395
|
+
setLoadingConversations(false);
|
|
396
|
+
}, 1000);
|
|
397
|
+
}}
|
|
398
|
+
onMessageListScrollTop={() => {
|
|
399
|
+
setLoadingMessages(true);
|
|
400
|
+
const nextMsgPage = msgPage + 1;
|
|
401
|
+
setTimeout(() => {
|
|
402
|
+
setPaginationConvo((prev) => ({
|
|
403
|
+
...prev,
|
|
404
|
+
messageList: [
|
|
405
|
+
...Array.from({ length: 10 }, (_, i) => ({
|
|
406
|
+
sender:
|
|
407
|
+
i % 2 === 0
|
|
408
|
+
? prev.members.find(
|
|
409
|
+
(m) => m.id !== currentUser.id,
|
|
410
|
+
)!
|
|
411
|
+
: currentUser,
|
|
412
|
+
messageBody: `Older message ${i + 1} from page ${nextMsgPage}`,
|
|
413
|
+
createdAt: dayjs()
|
|
414
|
+
.subtract(nextMsgPage * 10 + (10 - i), "minutes")
|
|
415
|
+
.toDate(),
|
|
416
|
+
})),
|
|
417
|
+
...prev.messageList,
|
|
418
|
+
],
|
|
419
|
+
}));
|
|
420
|
+
setMsgPage(nextMsgPage);
|
|
421
|
+
setLoadingMessages(false);
|
|
422
|
+
}, 1000);
|
|
423
|
+
}}
|
|
424
|
+
onChangeMessage={(e) => setPaginationMessage(e.target.value)}
|
|
425
|
+
onSendMessage={(updated) => {
|
|
426
|
+
setPaginationConvo(updated);
|
|
427
|
+
setPaginationMessage("");
|
|
428
|
+
setPaginationConvoList((prev) =>
|
|
429
|
+
sortByLatest(
|
|
430
|
+
prev.map((c) => (c.id === updated.id ? updated : c)),
|
|
431
|
+
),
|
|
432
|
+
);
|
|
433
|
+
}}
|
|
434
|
+
handleSelectedConversation={(id) => {
|
|
435
|
+
const found = paginationConvoList.find((c) => c.id === id);
|
|
436
|
+
if (found) setPaginationConvo(found);
|
|
437
|
+
}}
|
|
126
438
|
/>
|
|
127
439
|
</div>
|
|
128
440
|
</StorySection>
|
|
129
441
|
</>
|
|
130
442
|
);
|
|
131
|
-
}
|
|
443
|
+
}
|
|
@@ -1,23 +1,17 @@
|
|
|
1
|
-
import { storiesOf } from "@storybook/react";
|
|
2
1
|
import React from "react";
|
|
3
2
|
import { StorySection } from "../../storyUtils";
|
|
4
|
-
import
|
|
5
|
-
import { DataGraph } from "./index";
|
|
3
|
+
import { DataGraph as DataGraphImpl } from "./index";
|
|
6
4
|
|
|
7
|
-
const
|
|
5
|
+
const meta = { title: "Data/Data Graph" };
|
|
6
|
+
export default meta;
|
|
8
7
|
|
|
9
|
-
stories.addParameters({
|
|
10
|
-
readme: {
|
|
11
|
-
content: README,
|
|
12
|
-
},
|
|
13
|
-
});
|
|
14
8
|
|
|
15
9
|
const workspace = {
|
|
16
10
|
apiEndpoint: "http://localhost:3000/api",
|
|
17
11
|
apiEndpointType: "mongoDB" as const,
|
|
18
12
|
};
|
|
19
13
|
|
|
20
|
-
|
|
14
|
+
export const DataGraph = () => {
|
|
21
15
|
return (
|
|
22
16
|
<>
|
|
23
17
|
<StorySection
|
|
@@ -25,7 +19,7 @@ stories.add("Data Graph", () => {
|
|
|
25
19
|
description="type='card' renders a stat card. queryBaseType='count' counts records; 'sum' totals a numeric field specified in queryAttributeId. queryBaseDateId enables a date range picker on the card."
|
|
26
20
|
>
|
|
27
21
|
<div className="w-full">
|
|
28
|
-
<
|
|
22
|
+
<DataGraphImpl
|
|
29
23
|
charts={[
|
|
30
24
|
{
|
|
31
25
|
gridSize: 1,
|
|
@@ -56,10 +50,10 @@ stories.add("Data Graph", () => {
|
|
|
56
50
|
|
|
57
51
|
<StorySection
|
|
58
52
|
title="Mixed Dashboard"
|
|
59
|
-
description="Combine multiple chart types in one
|
|
53
|
+
description="Combine multiple chart types in one DataGraphImpl. Each chart's gridSize controls how many columns it spans within the grid."
|
|
60
54
|
>
|
|
61
55
|
<div className="w-full">
|
|
62
|
-
<
|
|
56
|
+
<DataGraphImpl
|
|
63
57
|
charts={[
|
|
64
58
|
{
|
|
65
59
|
gridSize: 1,
|
|
@@ -100,4 +94,4 @@ stories.add("Data Graph", () => {
|
|
|
100
94
|
</StorySection>
|
|
101
95
|
</>
|
|
102
96
|
);
|
|
103
|
-
}
|
|
97
|
+
}
|
|
@@ -1,24 +1,18 @@
|
|
|
1
|
-
import { storiesOf } from "@storybook/react";
|
|
2
1
|
import axios from "axios";
|
|
3
2
|
import React, { useState } from "react";
|
|
4
|
-
import { DataReference } from "../dataReference/index";
|
|
3
|
+
import { DataReference as DataReferenceImpl } from "../dataReference/index";
|
|
5
4
|
import { StorySection } from "../../storyUtils";
|
|
6
|
-
import README from "./README.md";
|
|
7
5
|
|
|
8
|
-
const
|
|
6
|
+
const meta = { title: "Data/Data Reference" };
|
|
7
|
+
export default meta;
|
|
9
8
|
|
|
10
|
-
stories.addParameters({
|
|
11
|
-
readme: {
|
|
12
|
-
content: README,
|
|
13
|
-
},
|
|
14
|
-
});
|
|
15
9
|
|
|
16
10
|
const devSettings = {
|
|
17
11
|
apiEndpoint: "http://localhost:3000/api",
|
|
18
12
|
apiEndpointType: "mondayServer" as const,
|
|
19
13
|
};
|
|
20
14
|
|
|
21
|
-
|
|
15
|
+
export const DataReference = () => {
|
|
22
16
|
const [singleValue, setSingleValue] = useState("");
|
|
23
17
|
const [filteredValue, setFilteredValue] = useState("");
|
|
24
18
|
const [multiValue, setMultiValue] = useState<string[]>([]);
|
|
@@ -30,7 +24,7 @@ stories.add("Data Reference", () => {
|
|
|
30
24
|
description="type='reference' renders a single-select. Options are fetched from the referenceSpaceId collection and labelled by referenceLabel."
|
|
31
25
|
>
|
|
32
26
|
<div className="w-80">
|
|
33
|
-
<
|
|
27
|
+
<DataReferenceImpl
|
|
34
28
|
value={singleValue}
|
|
35
29
|
schema={{
|
|
36
30
|
id: "salesSelected",
|
|
@@ -52,7 +46,7 @@ stories.add("Data Reference", () => {
|
|
|
52
46
|
description="referenceQuery filters the fetched options server-side. referenceSort controls the order. subLabel adds a secondary hint below the field label."
|
|
53
47
|
>
|
|
54
48
|
<div className="w-80">
|
|
55
|
-
<
|
|
49
|
+
<DataReferenceImpl
|
|
56
50
|
value={filteredValue}
|
|
57
51
|
schema={{
|
|
58
52
|
id: "filteredSales",
|
|
@@ -79,7 +73,7 @@ stories.add("Data Reference", () => {
|
|
|
79
73
|
description="type='listReference' enables multi-select — value is a string array. closeOnClickOutside keeps the dropdown open until the user clicks away."
|
|
80
74
|
>
|
|
81
75
|
<div className="w-80">
|
|
82
|
-
<
|
|
76
|
+
<DataReferenceImpl
|
|
83
77
|
value={multiValue}
|
|
84
78
|
schema={{
|
|
85
79
|
id: "assignees",
|
|
@@ -103,7 +97,7 @@ stories.add("Data Reference", () => {
|
|
|
103
97
|
dark
|
|
104
98
|
>
|
|
105
99
|
<div className="w-80">
|
|
106
|
-
<
|
|
100
|
+
<DataReferenceImpl
|
|
107
101
|
value={singleValue}
|
|
108
102
|
schema={{
|
|
109
103
|
id: "darkSales",
|
|
@@ -122,4 +116,4 @@ stories.add("Data Reference", () => {
|
|
|
122
116
|
</StorySection>
|
|
123
117
|
</>
|
|
124
118
|
);
|
|
125
|
-
}
|
|
119
|
+
}
|