diff --git a/rss-reader/asset-manifest.json b/rss-reader/asset-manifest.json
index f6e0615..ff634a3 100644
--- a/rss-reader/asset-manifest.json
+++ b/rss-reader/asset-manifest.json
@@ -1,8 +1,8 @@
{
"files": {
"main.css": "/custom-plugins/rss-reader/static/css/main.8c8b27cf.chunk.css",
- "main.js": "/custom-plugins/rss-reader/static/js/main.feea9f53.chunk.js",
- "main.js.map": "/custom-plugins/rss-reader/static/js/main.feea9f53.chunk.js.map",
+ "main.js": "/custom-plugins/rss-reader/static/js/main.317302ec.chunk.js",
+ "main.js.map": "/custom-plugins/rss-reader/static/js/main.317302ec.chunk.js.map",
"runtime-main.js": "/custom-plugins/rss-reader/static/js/runtime-main.3e5bd222.js",
"runtime-main.js.map": "/custom-plugins/rss-reader/static/js/runtime-main.3e5bd222.js.map",
"static/js/2.4d4df2b5.chunk.js": "/custom-plugins/rss-reader/static/js/2.4d4df2b5.chunk.js",
@@ -17,6 +17,6 @@
"static/js/runtime-main.3e5bd222.js",
"static/js/2.4d4df2b5.chunk.js",
"static/css/main.8c8b27cf.chunk.css",
- "static/js/main.feea9f53.chunk.js"
+ "static/js/main.317302ec.chunk.js"
]
}
\ No newline at end of file
diff --git a/rss-reader/index.html b/rss-reader/index.html
index ae20da7..e4b3a2c 100644
--- a/rss-reader/index.html
+++ b/rss-reader/index.html
@@ -1 +1 @@
-
React App
\ No newline at end of file
+React App
\ No newline at end of file
diff --git a/rss-reader/static/js/main.317302ec.chunk.js b/rss-reader/static/js/main.317302ec.chunk.js
new file mode 100644
index 0000000..499b6f8
--- /dev/null
+++ b/rss-reader/static/js/main.317302ec.chunk.js
@@ -0,0 +1,2 @@
+(this["webpackJsonpreact-app"]=this["webpackJsonpreact-app"]||[]).push([[0],{144:function(e,t,r){},145:function(e,t,r){},152:function(e,t){},154:function(e,t){},176:function(e,t){},206:function(e,t,r){"use strict";r.r(t);var a=r(0),n=r.n(a),c=r(121),s=r.n(c),o=(r(144),r(257)),i=r(255),d=(r(145),r(122)),l=r.n(d);var b=r(256),j=r(251),u=r(2);const h=e=>{let{feedTitle:t,rssFeedItem:r,onItemClick:n}=e;const c=Object(a.useCallback)((()=>{null===n||void 0===n||n(r)}),[n,r]),s=Object(a.useMemo)((()=>Object(j.a)(new Date(r.isoDate),"PPpp")),[r.isoDate]);return Object(u.jsxs)(i.a,{onClick:c,padding:1,sx:{backgroundColor:"#E6E5E5",borderWidth:"thin",borderStyle:"solid",borderColor:"#B8B8B8",borderRadius:"10px",cursor:"pointer",textAlign:"left"},children:[Object(u.jsx)(b.a,{fontWeight:"bold",variant:"body1",children:r.title}),Object(u.jsx)(b.a,{variant:"caption",sx:{overflow:"hidden",textOverflow:"ellipsis",display:"-webkit-box",WebkitLineClamp:2,WebkitBoxOrient:"vertical"},children:r.contentSnippet}),Object(u.jsx)(b.a,{alignSelf:"end",variant:"caption",children:s})]})};var x=r(254);const O=Object(a.memo)((()=>Object(u.jsxs)(i.a,{spacing:1,children:[Object(u.jsx)(x.a,{variant:"rectangular",height:60}),Object(u.jsx)(x.a,{variant:"rectangular",height:60}),Object(u.jsx)(x.a,{variant:"rectangular",height:60}),Object(u.jsx)(x.a,{variant:"rectangular",height:60}),Object(u.jsx)(x.a,{variant:"rectangular",height:60}),Object(u.jsx)(x.a,{variant:"rectangular",height:60}),Object(u.jsx)(x.a,{variant:"rectangular",height:60})]})));O.displayName="LoadingSkeleton";const g=e=>{let{onRssFeedItemClick:t,feedUrls:r}=e;const{feeds:n,loading:c,error:s}=(e=>{const[t,r]=Object(a.useState)([]),[n,c]=Object(a.useState)(!0),[s,o]=Object(a.useState)(null);return Object(a.useEffect)((()=>{(async()=>{try{c(!0),o(null);const t=new l.a,a=e.map((async e=>{try{return await t.parseURL(e)}catch(r){return console.error("Error parsing feed from ".concat(e,":"),r),null}})),n=(await Promise.all(a)).filter(Boolean);r(n),c(!1),o(null)}catch(s){r([]),c(!1),o("Error fetching RSS feeds")}})()}),[e]),{feeds:t,loading:n,error:s}})(r);return c?Object(u.jsx)(O,{}):s?Object(u.jsx)(b.a,{fontWeight:"bold",variant:"h5",children:"Error: ".concat(s)}):Object(u.jsxs)(i.a,{children:[0===n.length&&Object(u.jsx)(b.a,{variant:"h6",children:"No results found."}),n.map(((e,r)=>Object(u.jsxs)(a.Fragment,{children:[0===e.items.length&&Object(u.jsx)(b.a,{variant:"h6",children:"No results found."}),e.items.map((r=>Object(u.jsx)(h,{feedTitle:e.title,rssFeedItem:r,onItemClick:t},r.isoDate)))]},r)))]})};var p=r(252),v=r(127),f=r.n(v),m=r(128),C=r.n(m);const k=e=>{let{step:t,onAdd:r,onGoBack:a}=e;return Object(u.jsxs)(i.a,{flexDirection:"row",alignItems:"center",justifyContent:"space-between",children:["listFeed"===t&&Object(u.jsx)(b.a,{variant:"body2",children:"Feeder"}),"addFeed"===t&&Object(u.jsx)(b.a,{variant:"body2",children:"Add Feed"}),"listFeed"===t&&Object(u.jsx)(p.a,{sx:{width:"30px",height:"30px",borderRadius:0,backgroundColor:"#E6E5E5"},onClick:r,children:Object(u.jsx)(f.a,{})}),"listFeed"!==t&&Object(u.jsx)(p.a,{sx:{width:"30px",height:"30px",borderRadius:0,backgroundColor:"#E6E5E5"},onClick:a,children:Object(u.jsx)(C.a,{})})]})};var y=r(250),w=r(129),F=r.n(w);const B=e=>{let{rssFeedUrl:t,onChangeRssFeedUrl:r,feedUrls:a,onDelete:n,onAddRssFeedUrl:c}=e;return Object(u.jsxs)(i.a,{children:[Object(u.jsxs)(i.a,{flexDirection:"row",justifyContent:"space-between",padding:2,sx:{backgroundColor:"#E6E5E5",borderWidth:"thin",borderStyle:"solid",borderColor:"#B8B8B8",borderRadius:"10px"},children:[Object(u.jsx)(b.a,{variant:"body2",children:"Feed URL"}),Object(u.jsx)(y.a,{fullWidth:!0,value:t,variant:"outlined",size:"small",type:"url",onKeyDown:e=>{"Enter"===e.key&&c()},onChange:e=>r(e.target.value)})]}),Object(u.jsx)(i.a,{padding:3,sx:{backgroundColor:"#E6E5E5",borderWidth:"thin",borderStyle:"solid",borderColor:"#B8B8B8",borderRadius:"10px"},children:Object(u.jsx)(i.a,{sx:{backgroundColor:"white",borderWidth:"thin",borderStyle:"solid",borderColor:"#B8B8B8",borderRadius:"10px"},padding:1,children:a.map(((e,t)=>Object(u.jsxs)(i.a,{alignItems:"center",flexDirection:"row",justifyContent:"space-between",sx:{borderWidth:"thin",borderBottomStyle:"solid",borderBottomColor:"#B8B8B8"},children:[Object(u.jsx)(b.a,{variant:"body2",sx:{wordBreak:"break-all"},children:e}),Object(u.jsx)(p.a,{onClick:()=>null===n||void 0===n?void 0:n(t),children:Object(u.jsx)(F.a,{color:"error"})})]},t)))})})]})},E=e=>{var t;let{rssFeedItem:r}=e;return Object(u.jsxs)(i.a,{sx:{backgroundColor:"#E6E5E5",borderWidth:"medium",borderStyle:"solid",borderColor:"#B8B8B8",borderRadius:"10px",textAlign:"left",padding:2},spacing:3,children:[Object(u.jsxs)(i.a,{children:[Object(u.jsx)(b.a,{variant:"body2",children:Object(j.a)(new Date(r.isoDate),"PPpp")}),Object(u.jsx)(b.a,{variant:"h5",fontWeight:"bold",children:r.title}),(r.author||r.creator)&&Object(u.jsx)(b.a,{variant:"body2",children:"By ".concat(null===(t=r.author||r.creator)||void 0===t?void 0:t.replace("/u/",""))})]}),Object(u.jsx)(b.a,{variant:"body2",sx:{overflow:"auto"},dangerouslySetInnerHTML:{__html:r.content}})]})},S=[];var I=function(){const[e,t]=Object(a.useState)("listFeed"),[r,n]=Object(a.useState)(),[c,s]=Object(a.useState)(""),[d,l]=Object(a.useState)(),{updateValue:b,value:j,getValue:h}=(e=>{const[t,r]=Object(a.useState)(e);return{value:t,updateValue:Object(a.useCallback)(((e,t)=>{r(t),localStorage.setItem(e,JSON.stringify(t))}),[]),getValue:Object(a.useCallback)((t=>{const a=localStorage.getItem(t),n=a?JSON.parse(a):e;r(n)}),[e])}})(S);var x;x=Object(a.useCallback)((e=>{const t=e.data;"ovice_participant_joined"!==t.type&&"ovice_participant_subscribed"!==t.type||(l(t.payload.objectId),h("rss-reader-".concat(t.payload.objectId)))}),[h]),Object(a.useEffect)((()=>{const e=e=>{x(e)};return window.addEventListener("message",e),()=>{window.removeEventListener("message",e)}}),[x]);const O=Object(a.useCallback)((()=>{t("addFeed")}),[]),p=Object(a.useCallback)((()=>{t("listFeed")}),[]),v=Object(a.useCallback)((e=>{n(e),t("viewItem")}),[]),f=Object(a.useCallback)((()=>{if(!c.trim())return;const e=[...j];e.push(c),b("rss-reader-".concat(d),e),s("")}),[j,d,c,b]),m=Object(a.useCallback)((e=>{const t=[...j];t.splice(e,1),b("rss-reader-".concat(d),t)}),[j,d,b]);return Object(u.jsx)("div",{className:"App",children:Object(u.jsx)(o.a,{maxWidth:"sm",sx:{backgroundColor:"white"},children:Object(u.jsxs)(i.a,{spacing:1,padding:1,children:[Object(u.jsx)(k,{step:e,onAdd:O,onGoBack:p}),"addFeed"===e&&Object(u.jsx)(B,{onAddRssFeedUrl:f,rssFeedUrl:c,onChangeRssFeedUrl:s,feedUrls:j,onDelete:m}),"listFeed"===e&&Object(u.jsx)(g,{feedUrls:j,onRssFeedItemClick:v}),"viewItem"===e&&r&&Object(u.jsx)(E,{rssFeedItem:r})]})})})};var R=e=>{e&&e instanceof Function&&r.e(3).then(r.bind(null,258)).then((t=>{let{getCLS:r,getFID:a,getFCP:n,getLCP:c,getTTFB:s}=t;r(e),a(e),n(e),c(e),s(e)}))};s.a.createRoot(document.getElementById("root")).render(Object(u.jsx)(n.a.StrictMode,{children:Object(u.jsx)(I,{})})),R()}},[[206,1,2]]]);
+//# sourceMappingURL=main.317302ec.chunk.js.map
\ No newline at end of file
diff --git a/rss-reader/static/js/main.317302ec.chunk.js.map b/rss-reader/static/js/main.317302ec.chunk.js.map
new file mode 100644
index 0000000..771ba6c
--- /dev/null
+++ b/rss-reader/static/js/main.317302ec.chunk.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["components/RssFeedItemView.tsx","components/LoadingSkeleton.tsx","FeedList.tsx","hooks/useRssFeeds.tsx","components/NavigationTopBar.tsx","components/AddFeedsView.tsx","components/ArticleView.tsx","App.tsx","hooks/useLocalStorage.tsx","hooks/useMessageEventListener.tsx","reportWebVitals.ts","index.tsx"],"names":["RssFeedItemView","_ref","feedTitle","rssFeedItem","onItemClick","handleOnClick","useCallback","formattedDate","useMemo","format","Date","isoDate","_jsxs","Stack","onClick","padding","sx","backgroundColor","borderWidth","borderStyle","borderColor","borderRadius","cursor","textAlign","children","_jsx","Typography","fontWeight","variant","title","overflow","textOverflow","display","WebkitLineClamp","WebkitBoxOrient","contentSnippet","alignSelf","LoadingSkeleton","memo","spacing","Skeleton","height","displayName","FeedList","onRssFeedItemClick","feedUrls","feeds","loading","error","urls","setFeeds","useState","setLoading","setError","useEffect","async","parser","Parser","promises","map","parseURL","url","parseError","console","concat","fetchedFeeds","Promise","all","filter","Boolean","fetchFeeds","useRssFeeds","length","feed","index","Fragment","items","item","NavigationTopBar","step","onAdd","onGoBack","flexDirection","alignItems","justifyContent","IconButton","width","AddIcon","KeyboardArrowLeftIcon","AddFeedsView","rssFeedUrl","onChangeRssFeedUrl","onDelete","onAddRssFeedUrl","TextField","fullWidth","value","size","type","onKeyDown","e","key","onChange","target","feedUrl","borderBottomStyle","borderBottomColor","wordBreak","DeleteForeverIcon","color","ArticleView","_ref2","author","creator","replace","dangerouslySetInnerHTML","__html","content","defaultFeedUrlsValue","App","setStep","selectedFeedItem","setSelectedFeedItem","setRssFeedUrl","objectId","setObjectId","updateValue","getValue","initialValue","setValue","newValue","localStorage","setItem","JSON","stringify","storedValue","getItem","initial","parse","useLocalStorage","handleMessage","messageEvent","data","payload","eventListener","event","window","addEventListener","removeEventListener","handleOnAddNewFeed","handleOnGoBack","handleOnRssFeedItemClick","handleOnAddFeedUrl","trim","newFeedUrls","push","handleOnDeleteFeed","splice","className","Container","maxWidth","reportWebVitals","onPerfEntry","Function","then","getCLS","getFID","getFCP","getLCP","getTTFB","ReactDOM","createRoot","document","getElementById","render","React","StrictMode"],"mappings":"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","file":"static/js/main.317302ec.chunk.js","sourcesContent":["import { Stack, Typography } from \"@mui/material\";\nimport { RssFeedItem } from \"../hooks/useRssFeeds\";\nimport { useCallback, useMemo } from \"react\";\nimport { format } from \"date-fns\";\n\ntype RssFeedItemViewProps = {\n rssFeedItem: RssFeedItem;\n feedTitle?: string;\n onItemClick?: (rssFeedItem: RssFeedItem) => void;\n};\nexport const RssFeedItemView = ({\n feedTitle,\n rssFeedItem,\n onItemClick,\n}: RssFeedItemViewProps) => {\n const handleOnClick = useCallback(() => {\n onItemClick?.(rssFeedItem);\n }, [onItemClick, rssFeedItem]);\n\n const formattedDate = useMemo(() => {\n return format(new Date(rssFeedItem.isoDate), \"PPpp\");\n }, [rssFeedItem.isoDate]);\n return (\n \n \n {rssFeedItem.title}\n \n {/* {feedTitle} */}\n \n {rssFeedItem.contentSnippet}\n \n \n {formattedDate}\n \n \n );\n};\n","import { Skeleton, Stack } from \"@mui/material\";\nimport { memo } from \"react\";\n\nexport const LoadingSkeleton = memo(() => {\n return (\n \n \n \n \n \n \n \n \n \n );\n});\n\nLoadingSkeleton.displayName = \"LoadingSkeleton\";\n","import { Fragment } from \"react\";\nimport { RssFeedItem, useRssFeeds } from \"./hooks/useRssFeeds\";\nimport { RssFeedItemView } from \"./components/RssFeedItemView\";\nimport { Stack, Typography } from \"@mui/material\";\nimport { LoadingSkeleton } from \"./components/LoadingSkeleton\";\ntype FeedListProps = {\n onRssFeedItemClick: (rssFeedItem: RssFeedItem) => void;\n feedUrls: string[];\n};\nexport const FeedList = ({ onRssFeedItemClick, feedUrls }: FeedListProps) => {\n const { feeds, loading, error } = useRssFeeds(feedUrls);\n\n if (loading) {\n return ;\n }\n\n if (error) {\n return (\n \n {`Error: ${error}`}\n \n );\n }\n\n return (\n \n {feeds.length === 0 && (\n No results found.\n )}\n {feeds.map((feed, index) => (\n \n {feed.items.length === 0 && (\n No results found.\n )}\n {feed.items.map((item) => {\n return (\n \n );\n })}\n \n ))}\n \n );\n};\n","import { useState, useEffect } from \"react\";\nimport Parser from \"rss-parser\";\n\nconst CORS_PROXY = \"https://cors-anywhere.herokuapp.com/\";\n\nexport type RssFeedItem = {\n author: string;\n creator: string;\n content: string;\n contentSnippet: string;\n id?: string;\n pubDate: string;\n link: string;\n title: string;\n isoDate: string;\n categories?: string | string[];\n};\n\nexport type RssFeed = {\n title: string;\n link: string;\n description?: string;\n items: RssFeedItem[];\n};\n\nexport const useRssFeeds = (urls: string[]) => {\n const [feeds, setFeeds] = useState([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState(null);\n\n useEffect(() => {\n const fetchFeeds = async () => {\n try {\n setLoading(true);\n setError(null);\n\n const parser = new Parser();\n const promises = urls.map(async (url) => {\n try {\n const feed = await parser.parseURL(url);\n return feed;\n } catch (parseError) {\n console.error(`Error parsing feed from ${url}:`, parseError);\n return null;\n }\n });\n\n const fetchedFeeds = (await Promise.all(promises)).filter(Boolean);\n setFeeds(fetchedFeeds as []);\n setLoading(false);\n setError(null);\n } catch (error) {\n setFeeds([]);\n setLoading(false);\n setError(\"Error fetching RSS feeds\");\n }\n };\n\n fetchFeeds();\n }, [urls]);\n\n return { feeds, loading, error };\n};\n","import { IconButton, Stack, Typography } from \"@mui/material\";\nimport AddIcon from \"@mui/icons-material/Add\";\nimport KeyboardArrowLeftIcon from \"@mui/icons-material/KeyboardArrowLeft\";\n\ntype NavigationTopBarProps = {\n onAdd?: () => void;\n onGoBack?: () => void;\n step: \"listFeed\" | \"addFeed\" | \"viewItem\";\n};\nexport const NavigationTopBar = ({\n step,\n onAdd,\n onGoBack,\n}: NavigationTopBarProps) => {\n return (\n \n {step === \"listFeed\" && (\n {\"Feeder\"}\n )}\n {step === \"addFeed\" && (\n {\"Add Feed\"}\n )}\n {step === \"listFeed\" && (\n \n \n \n )}\n\n {step !== \"listFeed\" && (\n \n \n \n )}\n \n );\n};\n","import { IconButton, Stack, TextField, Typography } from \"@mui/material\";\nimport DeleteForeverIcon from \"@mui/icons-material/DeleteForever\";\nexport type AddFeedsViewProps = {\n feedUrls: string[];\n rssFeedUrl: string;\n onChangeRssFeedUrl: (feedUrl: string) => void;\n onAddRssFeedUrl: () => void;\n onDelete?: (index: number) => void;\n};\nexport const AddFeedsView = ({\n rssFeedUrl,\n onChangeRssFeedUrl,\n feedUrls,\n onDelete,\n onAddRssFeedUrl,\n}: AddFeedsViewProps) => {\n return (\n \n \n {\"Feed URL\"}\n {\n if (e.key === \"Enter\") {\n onAddRssFeedUrl();\n }\n }}\n onChange={(e) => onChangeRssFeedUrl(e.target.value)}\n />\n \n \n \n {feedUrls.map((feedUrl, index) => {\n return (\n \n {feedUrl}\n onDelete?.(index)}>\n \n \n \n );\n })}\n \n \n \n );\n};\n","import { Stack, Typography } from \"@mui/material\";\nimport { RssFeedItem } from \"../hooks/useRssFeeds\";\nimport { format } from \"date-fns\";\n\ntype ArticleViewProps = {\n rssFeedItem: RssFeedItem;\n};\nexport const ArticleView = ({ rssFeedItem }: ArticleViewProps) => {\n return (\n \n \n \n {format(new Date(rssFeedItem.isoDate), \"PPpp\")}\n \n \n {rssFeedItem.title}\n \n {(rssFeedItem.author || rssFeedItem.creator) && (\n {`By ${(\n rssFeedItem.author || rssFeedItem.creator\n )?.replace(\"/u/\", \"\")}`}\n )}\n \n\n \n \n );\n};\n","import { Container, Stack } from \"@mui/material\";\nimport \"./App.css\";\nimport { FeedList } from \"./FeedList\";\nimport { NavigationTopBar } from \"./components/NavigationTopBar\";\nimport { useCallback, useState } from \"react\";\nimport { RssFeedItem } from \"./hooks/useRssFeeds\";\nimport { AddFeedsView } from \"./components/AddFeedsView\";\nimport { ArticleView } from \"./components/ArticleView\";\nimport { useMessageEventListener } from \"./hooks/useMessageEventListener\";\nimport { useLocalStorage } from \"./hooks/useLocalStorage\";\ntype OvicePayloadType = {\n objectId: string;\n};\n\ntype OviceEvent = {\n type: \"ovice_participant_subscribed\" | \"ovice_participant_joined\";\n payload: OvicePayloadType;\n};\n\nconst defaultFeedUrlsValue: string[] = [];\nfunction App() {\n const [step, setStep] = useState<\"listFeed\" | \"addFeed\" | \"viewItem\">(\n \"listFeed\"\n );\n\n const [selectedFeedItem, setSelectedFeedItem] = useState<\n RssFeedItem | undefined\n >();\n const [rssFeedUrl, setRssFeedUrl] = useState(\"\");\n const [objectId, setObjectId] = useState();\n\n const {\n updateValue,\n value: feedUrls,\n getValue,\n } = useLocalStorage(defaultFeedUrlsValue);\n useMessageEventListener(\n useCallback(\n (messageEvent: MessageEvent) => {\n const data: OviceEvent = messageEvent.data;\n if (\n data.type === \"ovice_participant_joined\" ||\n data.type === \"ovice_participant_subscribed\"\n ) {\n setObjectId(data.payload.objectId);\n getValue(`rss-reader-${data.payload.objectId}`);\n }\n },\n [getValue]\n )\n );\n\n const handleOnAddNewFeed = useCallback(() => {\n setStep(\"addFeed\");\n }, []);\n\n const handleOnGoBack = useCallback(() => {\n setStep(\"listFeed\");\n }, []);\n\n const handleOnRssFeedItemClick = useCallback((rssFeedItem: RssFeedItem) => {\n setSelectedFeedItem(rssFeedItem);\n setStep(\"viewItem\");\n }, []);\n\n const handleOnAddFeedUrl = useCallback(() => {\n if (!rssFeedUrl.trim()) {\n return;\n }\n const newFeedUrls = [...feedUrls];\n newFeedUrls.push(rssFeedUrl);\n updateValue(`rss-reader-${objectId}`, newFeedUrls);\n setRssFeedUrl(\"\");\n }, [feedUrls, objectId, rssFeedUrl, updateValue]);\n\n const handleOnDeleteFeed = useCallback(\n (index: number) => {\n const newFeedUrls = [...feedUrls];\n newFeedUrls.splice(index, 1);\n updateValue(`rss-reader-${objectId}`, newFeedUrls);\n },\n [feedUrls, objectId, updateValue]\n );\n\n return (\n \n
\n \n \n {step === \"addFeed\" && (\n \n )}\n {step === \"listFeed\" && (\n \n )}\n {step === \"viewItem\" && selectedFeedItem && (\n \n )}\n \n \n
\n );\n}\n\nexport default App;\n","import { useCallback, useState } from \"react\";\n\nexport const useLocalStorage = (initialValue: T) => {\n const [value, setValue] = useState(initialValue);\n\n const updateValue = useCallback((key: string, newValue: T) => {\n setValue(newValue);\n localStorage.setItem(key, JSON.stringify(newValue));\n }, []);\n\n const getValue = useCallback(\n (key: string) => {\n const storedValue = localStorage.getItem(key);\n const initial = storedValue ? JSON.parse(storedValue) : initialValue;\n setValue(initial);\n },\n [initialValue]\n );\n\n return { value, updateValue, getValue };\n};\n","import { useEffect } from \"react\";\n\nexport const useMessageEventListener = (\n handleMessage: (event: MessageEvent) => void\n) => {\n useEffect(() => {\n const eventListener = (event: MessageEvent) => {\n handleMessage(event);\n };\n\n window.addEventListener(\"message\", eventListener);\n\n return () => {\n window.removeEventListener(\"message\", eventListener);\n };\n }, [handleMessage]);\n};\n","import { ReportHandler } from 'web-vitals';\n\nconst reportWebVitals = (onPerfEntry?: ReportHandler) => {\n if (onPerfEntry && onPerfEntry instanceof Function) {\n import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {\n getCLS(onPerfEntry);\n getFID(onPerfEntry);\n getFCP(onPerfEntry);\n getLCP(onPerfEntry);\n getTTFB(onPerfEntry);\n });\n }\n};\n\nexport default reportWebVitals;\n","import React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport './index.css';\nimport App from './App';\nimport reportWebVitals from './reportWebVitals';\n\n\nconst root = ReactDOM.createRoot(\n document.getElementById('root') as HTMLElement\n);\nroot.render(\n \n \n \n);\n\n// If you want to start measuring performance in your app, pass a function\n// to log results (for example: reportWebVitals(console.log))\n// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals\nreportWebVitals();\n"],"sourceRoot":""}
\ No newline at end of file
diff --git a/rss-reader/static/js/main.feea9f53.chunk.js b/rss-reader/static/js/main.feea9f53.chunk.js
deleted file mode 100644
index de374c4..0000000
--- a/rss-reader/static/js/main.feea9f53.chunk.js
+++ /dev/null
@@ -1,2 +0,0 @@
-(this["webpackJsonpreact-app"]=this["webpackJsonpreact-app"]||[]).push([[0],{144:function(e,t,r){},145:function(e,t,r){},152:function(e,t){},154:function(e,t){},176:function(e,t){},206:function(e,t,r){"use strict";r.r(t);var a=r(0),n=r.n(a),c=r(121),s=r.n(c),o=(r(144),r(257)),i=r(255),d=(r(145),r(122)),l=r.n(d);var b=r(256),j=r(251),u=r(2);const h=e=>{let{feedTitle:t,rssFeedItem:r,onItemClick:n}=e;const c=Object(a.useCallback)((()=>{null===n||void 0===n||n(r)}),[n,r]),s=Object(a.useMemo)((()=>Object(j.a)(new Date(r.isoDate),"PPpp")),[r.isoDate]);return Object(u.jsxs)(i.a,{onClick:c,padding:1,sx:{backgroundColor:"#E6E5E5",borderWidth:"thin",borderStyle:"solid",borderColor:"#B8B8B8",borderRadius:"10px",cursor:"pointer",textAlign:"left"},children:[Object(u.jsx)(b.a,{fontWeight:"bold",variant:"body1",children:r.title}),Object(u.jsx)(b.a,{variant:"caption",sx:{overflow:"hidden",textOverflow:"ellipsis",display:"-webkit-box",WebkitLineClamp:2,WebkitBoxOrient:"vertical"},children:r.contentSnippet}),Object(u.jsx)(b.a,{alignSelf:"end",variant:"caption",children:s})]})};var x=r(254);const O=Object(a.memo)((()=>Object(u.jsxs)(i.a,{spacing:1,children:[Object(u.jsx)(x.a,{variant:"rectangular",height:60}),Object(u.jsx)(x.a,{variant:"rectangular",height:60}),Object(u.jsx)(x.a,{variant:"rectangular",height:60}),Object(u.jsx)(x.a,{variant:"rectangular",height:60}),Object(u.jsx)(x.a,{variant:"rectangular",height:60}),Object(u.jsx)(x.a,{variant:"rectangular",height:60}),Object(u.jsx)(x.a,{variant:"rectangular",height:60})]})));O.displayName="LoadingSkeleton";const p=e=>{let{onRssFeedItemClick:t,feedUrls:r}=e;const{feeds:n,loading:c,error:s}=(e=>{const[t,r]=Object(a.useState)([]),[n,c]=Object(a.useState)(!0),[s,o]=Object(a.useState)(null);return Object(a.useEffect)((()=>{(async()=>{try{c(!0),o(null);const t=new l.a,a=e.map((async e=>{try{return await t.parseURL("https://cors-anywhere.herokuapp.com/"+e)}catch(r){return console.error("Error parsing feed from ".concat(e,":"),r),null}})),n=(await Promise.all(a)).filter(Boolean);r(n),c(!1),o(null)}catch(s){r([]),c(!1),o("Error fetching RSS feeds")}})()}),[e]),{feeds:t,loading:n,error:s}})(r);return c?Object(u.jsx)(O,{}):s?Object(u.jsx)(b.a,{fontWeight:"bold",variant:"h5",children:"Error: ".concat(s)}):Object(u.jsxs)(i.a,{children:[0===n.length&&Object(u.jsx)(b.a,{variant:"h6",children:"No results found."}),n.map(((e,r)=>Object(u.jsxs)(a.Fragment,{children:[0===e.items.length&&Object(u.jsx)(b.a,{variant:"h6",children:"No results found."}),e.items.map((r=>Object(u.jsx)(h,{feedTitle:e.title,rssFeedItem:r,onItemClick:t},r.isoDate)))]},r)))]})};var g=r(252),v=r(127),f=r.n(v),m=r(128),C=r.n(m);const k=e=>{let{step:t,onAdd:r,onGoBack:a}=e;return Object(u.jsxs)(i.a,{flexDirection:"row",alignItems:"center",justifyContent:"space-between",children:["listFeed"===t&&Object(u.jsx)(b.a,{variant:"body2",children:"Feeder"}),"addFeed"===t&&Object(u.jsx)(b.a,{variant:"body2",children:"Add Feed"}),"listFeed"===t&&Object(u.jsx)(g.a,{sx:{width:"30px",height:"30px",borderRadius:0,backgroundColor:"#E6E5E5"},onClick:r,children:Object(u.jsx)(f.a,{})}),"listFeed"!==t&&Object(u.jsx)(g.a,{sx:{width:"30px",height:"30px",borderRadius:0,backgroundColor:"#E6E5E5"},onClick:a,children:Object(u.jsx)(C.a,{})})]})};var y=r(250),w=r(129),F=r.n(w);const B=e=>{let{rssFeedUrl:t,onChangeRssFeedUrl:r,feedUrls:a,onDelete:n,onAddRssFeedUrl:c}=e;return Object(u.jsxs)(i.a,{children:[Object(u.jsxs)(i.a,{flexDirection:"row",justifyContent:"space-between",padding:2,sx:{backgroundColor:"#E6E5E5",borderWidth:"thin",borderStyle:"solid",borderColor:"#B8B8B8",borderRadius:"10px"},children:[Object(u.jsx)(b.a,{variant:"body2",children:"Feed URL"}),Object(u.jsx)(y.a,{fullWidth:!0,value:t,variant:"outlined",size:"small",type:"url",onKeyDown:e=>{"Enter"===e.key&&c()},onChange:e=>r(e.target.value)})]}),Object(u.jsx)(i.a,{padding:3,sx:{backgroundColor:"#E6E5E5",borderWidth:"thin",borderStyle:"solid",borderColor:"#B8B8B8",borderRadius:"10px"},children:Object(u.jsx)(i.a,{sx:{backgroundColor:"white",borderWidth:"thin",borderStyle:"solid",borderColor:"#B8B8B8",borderRadius:"10px"},padding:1,children:a.map(((e,t)=>Object(u.jsxs)(i.a,{alignItems:"center",flexDirection:"row",justifyContent:"space-between",sx:{borderWidth:"thin",borderBottomStyle:"solid",borderBottomColor:"#B8B8B8"},children:[Object(u.jsx)(b.a,{variant:"body2",sx:{wordBreak:"break-all"},children:e}),Object(u.jsx)(g.a,{onClick:()=>null===n||void 0===n?void 0:n(t),children:Object(u.jsx)(F.a,{color:"error"})})]},t)))})})]})},E=e=>{var t;let{rssFeedItem:r}=e;return Object(u.jsxs)(i.a,{sx:{backgroundColor:"#E6E5E5",borderWidth:"medium",borderStyle:"solid",borderColor:"#B8B8B8",borderRadius:"10px",textAlign:"left",padding:2},spacing:3,children:[Object(u.jsxs)(i.a,{children:[Object(u.jsx)(b.a,{variant:"body2",children:Object(j.a)(new Date(r.isoDate),"PPpp")}),Object(u.jsx)(b.a,{variant:"h5",fontWeight:"bold",children:r.title}),(r.author||r.creator)&&Object(u.jsx)(b.a,{variant:"body2",children:"By ".concat(null===(t=r.author||r.creator)||void 0===t?void 0:t.replace("/u/",""))})]}),Object(u.jsx)(b.a,{variant:"body2",sx:{overflow:"auto"},dangerouslySetInnerHTML:{__html:r.content}})]})},S=[];var I=function(){const[e,t]=Object(a.useState)("listFeed"),[r,n]=Object(a.useState)(),[c,s]=Object(a.useState)(""),[d,l]=Object(a.useState)(),{updateValue:b,value:j,getValue:h}=(e=>{const[t,r]=Object(a.useState)(e);return{value:t,updateValue:Object(a.useCallback)(((e,t)=>{r(t),localStorage.setItem(e,JSON.stringify(t))}),[]),getValue:Object(a.useCallback)((t=>{const a=localStorage.getItem(t),n=a?JSON.parse(a):e;r(n)}),[e])}})(S);var x;x=Object(a.useCallback)((e=>{const t=e.data;"ovice_participant_joined"!==t.type&&"ovice_participant_subscribed"!==t.type||(l(t.payload.objectId),h("rss-reader-".concat(t.payload.objectId)))}),[h]),Object(a.useEffect)((()=>{const e=e=>{x(e)};return window.addEventListener("message",e),()=>{window.removeEventListener("message",e)}}),[x]);const O=Object(a.useCallback)((()=>{t("addFeed")}),[]),g=Object(a.useCallback)((()=>{t("listFeed")}),[]),v=Object(a.useCallback)((e=>{n(e),t("viewItem")}),[]),f=Object(a.useCallback)((()=>{if(!c.trim())return;const e=[...j];e.push(c),b("rss-reader-".concat(d),e),s("")}),[j,d,c,b]),m=Object(a.useCallback)((e=>{const t=[...j];t.splice(e,1),b("rss-reader-".concat(d),t)}),[j,d,b]);return Object(u.jsx)("div",{className:"App",children:Object(u.jsx)(o.a,{maxWidth:"sm",sx:{backgroundColor:"white"},children:Object(u.jsxs)(i.a,{spacing:1,padding:1,children:[Object(u.jsx)(k,{step:e,onAdd:O,onGoBack:g}),"addFeed"===e&&Object(u.jsx)(B,{onAddRssFeedUrl:f,rssFeedUrl:c,onChangeRssFeedUrl:s,feedUrls:j,onDelete:m}),"listFeed"===e&&Object(u.jsx)(p,{feedUrls:j,onRssFeedItemClick:v}),"viewItem"===e&&r&&Object(u.jsx)(E,{rssFeedItem:r})]})})})};var R=e=>{e&&e instanceof Function&&r.e(3).then(r.bind(null,258)).then((t=>{let{getCLS:r,getFID:a,getFCP:n,getLCP:c,getTTFB:s}=t;r(e),a(e),n(e),c(e),s(e)}))};s.a.createRoot(document.getElementById("root")).render(Object(u.jsx)(n.a.StrictMode,{children:Object(u.jsx)(I,{})})),R()}},[[206,1,2]]]);
-//# sourceMappingURL=main.feea9f53.chunk.js.map
\ No newline at end of file
diff --git a/rss-reader/static/js/main.feea9f53.chunk.js.map b/rss-reader/static/js/main.feea9f53.chunk.js.map
deleted file mode 100644
index 7af673e..0000000
--- a/rss-reader/static/js/main.feea9f53.chunk.js.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"sources":["components/RssFeedItemView.tsx","components/LoadingSkeleton.tsx","FeedList.tsx","hooks/useRssFeeds.tsx","components/NavigationTopBar.tsx","components/AddFeedsView.tsx","components/ArticleView.tsx","App.tsx","hooks/useLocalStorage.tsx","hooks/useMessageEventListener.tsx","reportWebVitals.ts","index.tsx"],"names":["RssFeedItemView","_ref","feedTitle","rssFeedItem","onItemClick","handleOnClick","useCallback","formattedDate","useMemo","format","Date","isoDate","_jsxs","Stack","onClick","padding","sx","backgroundColor","borderWidth","borderStyle","borderColor","borderRadius","cursor","textAlign","children","_jsx","Typography","fontWeight","variant","title","overflow","textOverflow","display","WebkitLineClamp","WebkitBoxOrient","contentSnippet","alignSelf","LoadingSkeleton","memo","spacing","Skeleton","height","displayName","FeedList","onRssFeedItemClick","feedUrls","feeds","loading","error","urls","setFeeds","useState","setLoading","setError","useEffect","async","parser","Parser","promises","map","parseURL","url","parseError","console","concat","fetchedFeeds","Promise","all","filter","Boolean","fetchFeeds","useRssFeeds","length","feed","index","Fragment","items","item","NavigationTopBar","step","onAdd","onGoBack","flexDirection","alignItems","justifyContent","IconButton","width","AddIcon","KeyboardArrowLeftIcon","AddFeedsView","rssFeedUrl","onChangeRssFeedUrl","onDelete","onAddRssFeedUrl","TextField","fullWidth","value","size","type","onKeyDown","e","key","onChange","target","feedUrl","borderBottomStyle","borderBottomColor","wordBreak","DeleteForeverIcon","color","ArticleView","_ref2","author","creator","replace","dangerouslySetInnerHTML","__html","content","defaultFeedUrlsValue","App","setStep","selectedFeedItem","setSelectedFeedItem","setRssFeedUrl","objectId","setObjectId","updateValue","getValue","initialValue","setValue","newValue","localStorage","setItem","JSON","stringify","storedValue","getItem","initial","parse","useLocalStorage","handleMessage","messageEvent","data","payload","eventListener","event","window","addEventListener","removeEventListener","handleOnAddNewFeed","handleOnGoBack","handleOnRssFeedItemClick","handleOnAddFeedUrl","trim","newFeedUrls","push","handleOnDeleteFeed","splice","className","Container","maxWidth","reportWebVitals","onPerfEntry","Function","then","getCLS","getFID","getFCP","getLCP","getTTFB","ReactDOM","createRoot","document","getElementById","render","React","StrictMode"],"mappings":"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","file":"static/js/main.feea9f53.chunk.js","sourcesContent":["import { Stack, Typography } from \"@mui/material\";\nimport { RssFeedItem } from \"../hooks/useRssFeeds\";\nimport { useCallback, useMemo } from \"react\";\nimport { format } from \"date-fns\";\n\ntype RssFeedItemViewProps = {\n rssFeedItem: RssFeedItem;\n feedTitle?: string;\n onItemClick?: (rssFeedItem: RssFeedItem) => void;\n};\nexport const RssFeedItemView = ({\n feedTitle,\n rssFeedItem,\n onItemClick,\n}: RssFeedItemViewProps) => {\n const handleOnClick = useCallback(() => {\n onItemClick?.(rssFeedItem);\n }, [onItemClick, rssFeedItem]);\n\n const formattedDate = useMemo(() => {\n return format(new Date(rssFeedItem.isoDate), \"PPpp\");\n }, [rssFeedItem.isoDate]);\n return (\n \n \n {rssFeedItem.title}\n \n {/* {feedTitle} */}\n \n {rssFeedItem.contentSnippet}\n \n \n {formattedDate}\n \n \n );\n};\n","import { Skeleton, Stack } from \"@mui/material\";\nimport { memo } from \"react\";\n\nexport const LoadingSkeleton = memo(() => {\n return (\n \n \n \n \n \n \n \n \n \n );\n});\n\nLoadingSkeleton.displayName = \"LoadingSkeleton\";\n","import { Fragment } from \"react\";\nimport { RssFeedItem, useRssFeeds } from \"./hooks/useRssFeeds\";\nimport { RssFeedItemView } from \"./components/RssFeedItemView\";\nimport { Stack, Typography } from \"@mui/material\";\nimport { LoadingSkeleton } from \"./components/LoadingSkeleton\";\ntype FeedListProps = {\n onRssFeedItemClick: (rssFeedItem: RssFeedItem) => void;\n feedUrls: string[];\n};\nexport const FeedList = ({ onRssFeedItemClick, feedUrls }: FeedListProps) => {\n const { feeds, loading, error } = useRssFeeds(feedUrls);\n\n if (loading) {\n return ;\n }\n\n if (error) {\n return (\n \n {`Error: ${error}`}\n \n );\n }\n\n return (\n \n {feeds.length === 0 && (\n No results found.\n )}\n {feeds.map((feed, index) => (\n \n {feed.items.length === 0 && (\n No results found.\n )}\n {feed.items.map((item) => {\n return (\n \n );\n })}\n \n ))}\n \n );\n};\n","import { useState, useEffect } from \"react\";\nimport Parser from \"rss-parser\";\n\nconst CORS_PROXY = \"https://cors-anywhere.herokuapp.com/\";\n\nexport type RssFeedItem = {\n author: string;\n creator: string;\n content: string;\n contentSnippet: string;\n id?: string;\n pubDate: string;\n link: string;\n title: string;\n isoDate: string;\n categories?: string | string[];\n};\n\nexport type RssFeed = {\n title: string;\n link: string;\n description?: string;\n items: RssFeedItem[];\n};\n\nexport const useRssFeeds = (urls: string[]) => {\n const [feeds, setFeeds] = useState([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState(null);\n\n useEffect(() => {\n const fetchFeeds = async () => {\n try {\n setLoading(true);\n setError(null);\n\n const parser = new Parser();\n const promises = urls.map(async (url) => {\n try {\n const feed = await parser.parseURL(CORS_PROXY + url);\n return feed;\n } catch (parseError) {\n console.error(`Error parsing feed from ${url}:`, parseError);\n return null;\n }\n });\n\n const fetchedFeeds = (await Promise.all(promises)).filter(Boolean);\n setFeeds(fetchedFeeds as []);\n setLoading(false);\n setError(null);\n } catch (error) {\n setFeeds([]);\n setLoading(false);\n setError(\"Error fetching RSS feeds\");\n }\n };\n\n fetchFeeds();\n }, [urls]);\n\n return { feeds, loading, error };\n};\n","import { IconButton, Stack, Typography } from \"@mui/material\";\nimport AddIcon from \"@mui/icons-material/Add\";\nimport KeyboardArrowLeftIcon from \"@mui/icons-material/KeyboardArrowLeft\";\n\ntype NavigationTopBarProps = {\n onAdd?: () => void;\n onGoBack?: () => void;\n step: \"listFeed\" | \"addFeed\" | \"viewItem\";\n};\nexport const NavigationTopBar = ({\n step,\n onAdd,\n onGoBack,\n}: NavigationTopBarProps) => {\n return (\n \n {step === \"listFeed\" && (\n {\"Feeder\"}\n )}\n {step === \"addFeed\" && (\n {\"Add Feed\"}\n )}\n {step === \"listFeed\" && (\n \n \n \n )}\n\n {step !== \"listFeed\" && (\n \n \n \n )}\n \n );\n};\n","import { IconButton, Stack, TextField, Typography } from \"@mui/material\";\nimport DeleteForeverIcon from \"@mui/icons-material/DeleteForever\";\nexport type AddFeedsViewProps = {\n feedUrls: string[];\n rssFeedUrl: string;\n onChangeRssFeedUrl: (feedUrl: string) => void;\n onAddRssFeedUrl: () => void;\n onDelete?: (index: number) => void;\n};\nexport const AddFeedsView = ({\n rssFeedUrl,\n onChangeRssFeedUrl,\n feedUrls,\n onDelete,\n onAddRssFeedUrl,\n}: AddFeedsViewProps) => {\n return (\n \n \n {\"Feed URL\"}\n {\n if (e.key === \"Enter\") {\n onAddRssFeedUrl();\n }\n }}\n onChange={(e) => onChangeRssFeedUrl(e.target.value)}\n />\n \n \n \n {feedUrls.map((feedUrl, index) => {\n return (\n \n {feedUrl}\n onDelete?.(index)}>\n \n \n \n );\n })}\n \n \n \n );\n};\n","import { Stack, Typography } from \"@mui/material\";\nimport { RssFeedItem } from \"../hooks/useRssFeeds\";\nimport { format } from \"date-fns\";\n\ntype ArticleViewProps = {\n rssFeedItem: RssFeedItem;\n};\nexport const ArticleView = ({ rssFeedItem }: ArticleViewProps) => {\n return (\n \n \n \n {format(new Date(rssFeedItem.isoDate), \"PPpp\")}\n \n \n {rssFeedItem.title}\n \n {(rssFeedItem.author || rssFeedItem.creator) && (\n {`By ${(\n rssFeedItem.author || rssFeedItem.creator\n )?.replace(\"/u/\", \"\")}`}\n )}\n \n\n \n \n );\n};\n","import { Container, Stack } from \"@mui/material\";\nimport \"./App.css\";\nimport { FeedList } from \"./FeedList\";\nimport { NavigationTopBar } from \"./components/NavigationTopBar\";\nimport { useCallback, useState } from \"react\";\nimport { RssFeedItem } from \"./hooks/useRssFeeds\";\nimport { AddFeedsView } from \"./components/AddFeedsView\";\nimport { ArticleView } from \"./components/ArticleView\";\nimport { useMessageEventListener } from \"./hooks/useMessageEventListener\";\nimport { useLocalStorage } from \"./hooks/useLocalStorage\";\ntype OvicePayloadType = {\n objectId: string;\n};\n\ntype OviceEvent = {\n type: \"ovice_participant_subscribed\" | \"ovice_participant_joined\";\n payload: OvicePayloadType;\n};\n\nconst defaultFeedUrlsValue: string[] = [];\nfunction App() {\n const [step, setStep] = useState<\"listFeed\" | \"addFeed\" | \"viewItem\">(\n \"listFeed\"\n );\n\n const [selectedFeedItem, setSelectedFeedItem] = useState<\n RssFeedItem | undefined\n >();\n const [rssFeedUrl, setRssFeedUrl] = useState(\"\");\n const [objectId, setObjectId] = useState();\n\n const {\n updateValue,\n value: feedUrls,\n getValue,\n } = useLocalStorage(defaultFeedUrlsValue);\n useMessageEventListener(\n useCallback(\n (messageEvent: MessageEvent) => {\n const data: OviceEvent = messageEvent.data;\n if (\n data.type === \"ovice_participant_joined\" ||\n data.type === \"ovice_participant_subscribed\"\n ) {\n setObjectId(data.payload.objectId);\n getValue(`rss-reader-${data.payload.objectId}`);\n }\n },\n [getValue]\n )\n );\n\n const handleOnAddNewFeed = useCallback(() => {\n setStep(\"addFeed\");\n }, []);\n\n const handleOnGoBack = useCallback(() => {\n setStep(\"listFeed\");\n }, []);\n\n const handleOnRssFeedItemClick = useCallback((rssFeedItem: RssFeedItem) => {\n setSelectedFeedItem(rssFeedItem);\n setStep(\"viewItem\");\n }, []);\n\n const handleOnAddFeedUrl = useCallback(() => {\n if (!rssFeedUrl.trim()) {\n return;\n }\n const newFeedUrls = [...feedUrls];\n newFeedUrls.push(rssFeedUrl);\n updateValue(`rss-reader-${objectId}`, newFeedUrls);\n setRssFeedUrl(\"\");\n }, [feedUrls, objectId, rssFeedUrl, updateValue]);\n\n const handleOnDeleteFeed = useCallback(\n (index: number) => {\n const newFeedUrls = [...feedUrls];\n newFeedUrls.splice(index, 1);\n updateValue(`rss-reader-${objectId}`, newFeedUrls);\n },\n [feedUrls, objectId, updateValue]\n );\n\n return (\n \n
\n \n \n {step === \"addFeed\" && (\n \n )}\n {step === \"listFeed\" && (\n \n )}\n {step === \"viewItem\" && selectedFeedItem && (\n \n )}\n \n \n
\n );\n}\n\nexport default App;\n","import { useCallback, useState } from \"react\";\n\nexport const useLocalStorage = (initialValue: T) => {\n const [value, setValue] = useState(initialValue);\n\n const updateValue = useCallback((key: string, newValue: T) => {\n setValue(newValue);\n localStorage.setItem(key, JSON.stringify(newValue));\n }, []);\n\n const getValue = useCallback(\n (key: string) => {\n const storedValue = localStorage.getItem(key);\n const initial = storedValue ? JSON.parse(storedValue) : initialValue;\n setValue(initial);\n },\n [initialValue]\n );\n\n return { value, updateValue, getValue };\n};\n","import { useEffect } from \"react\";\n\nexport const useMessageEventListener = (\n handleMessage: (event: MessageEvent) => void\n) => {\n useEffect(() => {\n const eventListener = (event: MessageEvent) => {\n handleMessage(event);\n };\n\n window.addEventListener(\"message\", eventListener);\n\n return () => {\n window.removeEventListener(\"message\", eventListener);\n };\n }, [handleMessage]);\n};\n","import { ReportHandler } from 'web-vitals';\n\nconst reportWebVitals = (onPerfEntry?: ReportHandler) => {\n if (onPerfEntry && onPerfEntry instanceof Function) {\n import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {\n getCLS(onPerfEntry);\n getFID(onPerfEntry);\n getFCP(onPerfEntry);\n getLCP(onPerfEntry);\n getTTFB(onPerfEntry);\n });\n }\n};\n\nexport default reportWebVitals;\n","import React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport './index.css';\nimport App from './App';\nimport reportWebVitals from './reportWebVitals';\n\n\nconst root = ReactDOM.createRoot(\n document.getElementById('root') as HTMLElement\n);\nroot.render(\n \n \n \n);\n\n// If you want to start measuring performance in your app, pass a function\n// to log results (for example: reportWebVitals(console.log))\n// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals\nreportWebVitals();\n"],"sourceRoot":""}
\ No newline at end of file