Skip to content

Commit

Permalink
Implement subscription message
Browse files Browse the repository at this point in the history
  • Loading branch information
alhamda committed May 23, 2023
1 parent f875181 commit c0d8e86
Show file tree
Hide file tree
Showing 12 changed files with 150 additions and 4,665 deletions.
4,610 changes: 0 additions & 4,610 deletions package-lock.json

This file was deleted.

6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,21 @@
"@headlessui/react": "^1.7.14",
"@reduxjs/toolkit": "^1.9.5",
"clsx": "^1.2.1",
"randomstring": "^1.2.3",
"rc-json-view": "^1.21.8",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-redux": "^8.0.5",
"react-router-dom": "^6.11.2"
"react-router-dom": "^6.11.2",
"redux-persist": "^6.0.0",
"uuid": "^9.0.0"
},
"devDependencies": {
"@tailwindcss/forms": "^0.5.3",
"@types/node": "^20.2.1",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"@types/uuid": "^9.0.1",
"@typescript-eslint/eslint-plugin": "^5.57.1",
"@typescript-eslint/parser": "^5.57.1",
"@vitejs/plugin-react": "^4.0.0",
Expand Down
2 changes: 1 addition & 1 deletion src/components/UI/SubscriptionBubble.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export default function SubscriptionBubble({ subscriptionItem }: { subscriptionI

return (
<div className="mb-6">
<div className="w-min min-w-[25rem] bg-white rounded-lg rounded-tl-none border max-w-[70%]">
<div className="bg-white rounded-md border">
<div className="pt-4 px-4 flex items-center">
<div className="text-xs w-full text-gray-500 line-clamp-1 break-all">Topic: {subscriptionItem.topic}</div>
<div className="ml-2 text-xs text-gray-500 flex-shrink-0">QoS: {subscriptionItem.qos}</div>
Expand Down
8 changes: 4 additions & 4 deletions src/components/UI/SubscriptionItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ export default function SubscriptionItem({
onClick: any
}) {
const dispatch = useAppDispatch();
function remove(){

function remove() {
dispatch(removeSubscription(subscription));
}

return (
<div className={clsx('transition-all group cursor-pointer flex items-center justify-between space-x-5 p-3 border-b w-full border-r-[2.5px]', isSelected ? 'border-r-emerald-500 text-emerald-500 font-medium bg-emerald-50/30 hover:bg-emerald-50/30' : 'hover:bg-slate-50 text-slate-600 border-r-transparent')} onClick={onClick}>
<div className="relative flex flex-col space-y-1 px-2 group">
<div className={clsx('transition-all group cursor-pointer flex items-center justify-between space-x-5 p-3 border-b w-full border-r-[2.5px]', isSelected ? 'border-r-emerald-500 text-emerald-500 font-medium bg-emerald-50/30 hover:bg-emerald-50/30' : 'hover:bg-slate-50 text-slate-600 border-r-transparent')}>
<div className="grow flex flex-col space-y-1 px-2 group" onClick={onClick}>
<div className="line-clamp-1 break-all text-sm">{subscription.topic}</div>
<div className="text-gray-400 flex-shrink-0 text-xs font-normal">Qos {subscription.qos}</div>
</div>
Expand Down
12 changes: 9 additions & 3 deletions src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,18 @@ import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import '@/assets/base.css';
import { Provider } from 'react-redux';
import {store} from './redux/store';
import { store } from './redux/store';
import { PersistGate } from 'redux-persist/integration/react'
import { persistStore } from 'redux-persist'

let persistor = persistStore(store);

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<Provider store={store}>
<App />
<PersistGate loading={null} persistor={persistor}>
<App />
</PersistGate>
</Provider>
</React.StrictMode>,
)
)
4 changes: 2 additions & 2 deletions src/pages/components/Publish.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ export default function Publish() {
<div className="flex items-center px-3 text-gray-700">
<span>QoS:</span>
<select className="ml-2 block w-full px-4 py-2 text-gray-700 placeholder-gray-400 border border-transparent focus:border-gray-400 focus:ring-gray-400 transition-colors focus:outline-none focus:ring-0 focus:ring-opacity-40 min-w-[70px]">
<option>0</option>
<option selected={true}>1</option>
<option selected>0</option>
<option>1</option>
<option>2</option>
</select>
</div>
Expand Down
40 changes: 35 additions & 5 deletions src/pages/components/Subscription.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ import Publish from "@/pages/components/Publish";
import SubscriptionModal from "@/pages/components/SubscriptionModal";
import { useAppSelector } from "@/redux/hooks";
import { selectSubscriptionItems, selectSubscriptions } from "@/redux/slices/mqttSlice";
import { useState } from "react";
import { useEffect, useRef, useState } from "react";

const AlwaysScrollToBottom = () => {
const elementRef = useRef<null | HTMLDivElement>(null);
useEffect(() => elementRef.current?.scrollIntoView({ behavior: "smooth" }));
return <div ref={elementRef} />;
};

export default function Subscription() {

Expand All @@ -14,6 +20,18 @@ export default function Subscription() {
const [subscriptionId, setSubscriptionId] = useState<string>('');
const [showModal, setShowModal] = useState(false);

const messagesEndRef = useRef<null | HTMLDivElement>(null);

const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" })
}

useEffect(() => {
setInterval(() => {
scrollToBottom()
}, 1000);
}, [subscriptionItems]);

return (
<>
{showModal && <SubscriptionModal isOpen={showModal} setIsOpen={setShowModal} />}
Expand Down Expand Up @@ -60,17 +78,29 @@ export default function Subscription() {
</div>
</div>
<div className="p-5 h-full w-full overflow-y-auto bg-gray-100 min-h-[500px] max-h-full">
{subscriptionItems.filter((item) => item.subscriptionId == subscriptionId).map((item) => {
{subscriptionItems.filter((item) => {
if (subscriptionId) {
return item.subscriptionId == subscriptionId;
} else {
return true;
}
}).map((item) => {
return <SubscriptionBubble key={item.id} subscriptionItem={item} />;
})}

{(subscriptionId && subscriptionItems.length > 0) && <AlwaysScrollToBottom />}

{subscriptionItems.length == 0 && <div className="flex w-full h-full items-center justify-center flex-col">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="hidden w-20 h-20 text-gray-400">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-20 h-20 text-gray-400/70">
<path strokeLinecap="round" strokeLinejoin="round" d="M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z" />
</svg>

<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="hidden w-20 h-20 text-gray-400/70">
<path strokeLinecap="round" strokeLinejoin="round" d="M15.59 14.37a6 6 0 01-5.84 7.38v-4.8m5.84-2.58a14.98 14.98 0 006.16-12.12A14.98 14.98 0 009.631 8.41m5.96 5.96a14.926 14.926 0 01-5.841 2.58m-.119-8.54a6 6 0 00-7.381 5.84h4.8m2.581-5.84a14.927 14.927 0 00-2.58 5.84m2.699 2.7c-.103.021-.207.041-.311.06a15.09 15.09 0 01-2.448-2.448 14.9 14.9 0 01.06-.312m-2.24 2.39a4.493 4.493 0 00-1.757 4.306 4.493 4.493 0 004.306-1.758M16.5 9a1.5 1.5 0 11-3 0 1.5 1.5 0 013 0z" />
</svg>

<div className="mt-4 font-medium text-xl text-gray-400">No Data Received</div>
<div className="mt-2 text-gray-400">Please select or create new subscription</div>
<div className="mt-4 font-medium text-xl text-gray-400/70">No Data Received</div>
<div className="mt-2 text-gray-400/70">Please select or create new subscription</div>
</div>}
</div>
<div className="bg-white w-full border-t rounded-br-md">
Expand Down
37 changes: 33 additions & 4 deletions src/pages/components/SubscriptionModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { Fragment, useState } from 'react'
import { Dialog, Transition } from '@headlessui/react'
import Required from '@/components/UI/Required';
import { useAppDispatch } from '@/redux/hooks';
import { addSubscription } from '@/redux/slices/mqttSlice';
import { addSubscription, addSubscriptionItem } from '@/redux/slices/mqttSlice';
import { v4 as uuidv4 } from 'uuid';
import { Subscription, SubscriptionItem } from '@/models/Subscription';

const SubscriptionModal = (
{ isOpen, setIsOpen }:
Expand All @@ -19,12 +21,39 @@ const SubscriptionModal = (
}

function doAdd() {
dispatch(addSubscription({
id: Math.random().toString(),
let subscriptionId = uuidv4();
let subscriptionItemId = uuidv4();
let subscriptionItemId2 = uuidv4();

let subscription: Subscription = {
id: subscriptionId,
qos: +qos,
topic
}));
};

let subscriptionItem: SubscriptionItem = {
id: subscriptionItemId,
subscriptionId: subscriptionId,
date: new Date(),
message: JSON.stringify(subscription),
qos: subscription.qos,
topic: subscription.topic,
}

let subscriptionItem2: SubscriptionItem = {
id: Math.random().toString(),
subscriptionId: subscriptionId,
date: new Date(),
message: JSON.stringify(subscriptionItem),
qos: subscription.qos,
topic: subscription.topic,
}

dispatch(addSubscription(subscription));
dispatch(addSubscriptionItem(subscriptionItem));
dispatch(addSubscriptionItem(subscriptionItem2));


closeModal();
}

Expand Down
27 changes: 0 additions & 27 deletions src/redux/slices/authSlice.ts

This file was deleted.

11 changes: 7 additions & 4 deletions src/redux/slices/mqttSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,14 @@ export const mqttSlice = createSlice({
state.subscriptions.push(payload);
},
removeSubscription: (state, { payload }: { payload: Subscription }) => {
state.subscriptions = state.subscriptions.filter((subscription) => subscription.id != payload.id);
state.subscriptionItems = state.subscriptionItems.filter((item) => item.subscriptionId != payload.id);
return {
...state,
subscriptions: state.subscriptions.filter((subscription) => subscription.id != payload.id),
subscriptionItems: state.subscriptionItems.filter((item) => item.subscriptionId != payload.id)
}
},
addSubscriptionItem: (state, action) => {
state.subscriptionItems.push(action.payload);
addSubscriptionItem: (state, { payload }: { payload: SubscriptionItem }) => {
state.subscriptionItems.push(payload);
}
},
});
Expand Down
25 changes: 21 additions & 4 deletions src/redux/store.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,32 @@
import {
Action,
combineReducers,
configureStore,
ThunkAction,
} from '@reduxjs/toolkit';

import { persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage'
import { getDefaultMiddleware } from '@reduxjs/toolkit';
import mqttSlice from '@/redux/slices/mqttSlice';

const persistConfig = {
key: 'root',
storage
};

const reducers = combineReducers({
mqtt: mqttSlice,
});

const persistedReducer = persistReducer(persistConfig, reducers);

const customizedMiddleware = getDefaultMiddleware({
serializableCheck: false
});

export const store = configureStore({
reducer: {
mqtt: mqttSlice,
},
reducer: persistedReducer,
middleware: customizedMiddleware,
});

export type AppDispatch = typeof store.dispatch;
Expand Down
33 changes: 33 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,11 @@
resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43"
integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==

"@types/uuid@^9.0.1":
version "9.0.1"
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.1.tgz#98586dc36aee8dacc98cc396dbca8d0429647aa6"
integrity sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA==

"@typescript-eslint/eslint-plugin@^5.57.1":
version "5.59.6"
resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.6.tgz"
Expand Down Expand Up @@ -685,6 +690,11 @@ array-union@^2.1.0:
resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz"
integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==

array-uniq@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.2.tgz#5fcc373920775723cfd64d65c64bef53bf9eba6d"
integrity sha512-GVYjmpL05al4dNlKJm53mKE4w9OOLiuVHWorsIA3YVz+Hu0hcn6PtE3Ydl0EqU7v+7ABC4mjjWsnLUxbpno+CA==

asap@~2.0.3:
version "2.0.6"
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
Expand Down Expand Up @@ -1711,6 +1721,19 @@ queue-microtask@^1.2.2:
resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==

randombytes@2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.3.tgz#674c99760901c3c4112771a31e521dc349cc09ec"
integrity sha512-lDVjxQQFoCG1jcrP06LNo2lbWp4QTShEXnhActFBwYuHprllQV6VUpwreApsYqCgD+N1mHoqJ/BI/4eV4R2GYg==

randomstring@^1.2.3:
version "1.2.3"
resolved "https://registry.yarnpkg.com/randomstring/-/randomstring-1.2.3.tgz#49d2bc34ff6bc2bd0f6bb8e7d876e1d4433564c8"
integrity sha512-3dEFySepTzp2CvH6W/ASYGguPPveBuz5MpZ7MuoUkoVehmyNl9+F9c9GFVrz2QPbM9NXTIHGcmJDY/3j4677kQ==
dependencies:
array-uniq "1.0.2"
randombytes "2.0.3"

rc-json-view@^1.21.8:
version "1.21.8"
resolved "https://registry.yarnpkg.com/rc-json-view/-/rc-json-view-1.21.8.tgz#2b110edd64e80241e26de376720e55d58adb4c48"
Expand Down Expand Up @@ -1816,6 +1839,11 @@ readdirp@~3.6.0:
dependencies:
picomatch "^2.2.1"

redux-persist@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/redux-persist/-/redux-persist-6.0.0.tgz#b4d2972f9859597c130d40d4b146fecdab51b3a8"
integrity sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ==

redux-thunk@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.4.2.tgz#b9d05d11994b99f7a91ea223e8b04cf0afa5ef3b"
Expand Down Expand Up @@ -2114,6 +2142,11 @@ util-deprecate@^1.0.2:
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==

uuid@^9.0.0:
version "9.0.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5"
integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==

vite@^4.3.2:
version "4.3.8"
resolved "https://registry.npmjs.org/vite/-/vite-4.3.8.tgz"
Expand Down

0 comments on commit c0d8e86

Please sign in to comment.