From 25cc4b667caae39b6a1d68a11a3ca9b3f6b39778 Mon Sep 17 00:00:00 2001 From: emargetis Date: Fri, 19 Apr 2024 18:42:13 -0500 Subject: [PATCH] feat (case-study): Added interactive todo list component Co-authored-by: Alex Sklar Co-authored-by: Franco Waisfeld Co-authored-by: Joseph Liang --- package-lock.json | 21 +++- package.json | 3 +- src/components/TodoList/TodoList.js | 77 ++++++++++++ src/components/TodoList/TodoListClient.js | 130 +++++++++++++++++++++ src/components/TodoList/icon_add.png | Bin 0 -> 498 bytes src/components/TodoList/icon_delete.png | Bin 0 -> 219 bytes src/components/TodoList/signal.svg | 4 + src/components/TodoList/signalVertical.svg | 4 + src/pages/case-study.mdx | 35 +++--- 9 files changed, 248 insertions(+), 26 deletions(-) create mode 100644 src/components/TodoList/TodoList.js create mode 100644 src/components/TodoList/TodoListClient.js create mode 100644 src/components/TodoList/icon_add.png create mode 100644 src/components/TodoList/icon_delete.png create mode 100644 src/components/TodoList/signal.svg create mode 100644 src/components/TodoList/signalVertical.svg diff --git a/package-lock.json b/package-lock.json index b81d395..5c6620a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,8 @@ "react-dom": "^18.0.0", "rehype-katex": "^6.0.3", "remark-math": "^5.1.1", - "tailwindcss": "^3.4.3" + "tailwindcss": "^3.4.3", + "uuid": "^9.0.1" }, "devDependencies": { "@docusaurus/eslint-plugin": "^3.2.1", @@ -15207,6 +15208,14 @@ "websocket-driver": "^0.7.4" } }, + "node_modules/sockjs/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/sort-css-media-queries": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/sort-css-media-queries/-/sort-css-media-queries-2.1.0.tgz", @@ -16510,9 +16519,13 @@ } }, "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "bin": { "uuid": "dist/bin/uuid" } diff --git a/package.json b/package.json index 0f17bc3..715035f 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,8 @@ "react-dom": "^18.0.0", "rehype-katex": "^6.0.3", "remark-math": "^5.1.1", - "tailwindcss": "^3.4.3" + "tailwindcss": "^3.4.3", + "uuid": "^9.0.1" }, "devDependencies": { "@docusaurus/eslint-plugin": "^3.2.1", diff --git a/src/components/TodoList/TodoList.js b/src/components/TodoList/TodoList.js new file mode 100644 index 0000000..0e7938b --- /dev/null +++ b/src/components/TodoList/TodoList.js @@ -0,0 +1,77 @@ +import { useState, useEffect } from 'react' +import { TodoListClient } from './TodoListClient.js' +import Signal from '../Puzzle/Signal.jsx' +import SignalVertical from '../Puzzle/SignalVertical.jsx' + +export default function TodoList() { + const [todoList, setTodoList] = useState([]) + const [windowWidth, setWindowWidth] = useState() + + useEffect(() => { + setWindowWidth(window.innerWidth) + window.addEventListener('resize', e => setWindowWidth(e.target.innerWidth)) + }, []) + + function handleSubmit(newTodo) { + let newTodoList = [...todoList, newTodo] + + setTodoList(newTodoList) + } + + function handleDelete(id) { + let filteredTodoList = todoList.filter(todo => todo.id !== id) + setTodoList(filteredTodoList) + } + + const divStyle = { + border: '40px solid', + borderImage: 'url(' + '/landing/Client-window2.svg' + ') 25 25', + } + if (windowWidth < 1094) { + return ( +
+ + + +
+ ) + } + + return ( +
+ + + +
+ ) +} diff --git a/src/components/TodoList/TodoListClient.js b/src/components/TodoList/TodoListClient.js new file mode 100644 index 0000000..c2d5e26 --- /dev/null +++ b/src/components/TodoList/TodoListClient.js @@ -0,0 +1,130 @@ +import { useEffect, useState } from 'react' +import { v4 as uuidv4 } from 'uuid' +import addIcon from './icon_add.png' +import deleteIcon from './icon_delete.png' + +export function TodoListClient({ + serverTodoList, + onSubmit, + onDelete, + latency, + interactable, + narrow, +}) { + const [inputValue, setInputValue] = useState('') + const [localTodoList, setLocalTodoList] = useState(serverTodoList) + const [displayErrorMessage, setDisplayErrorMessage] = useState(false) + + useEffect(() => { + setTimeout(() => { + setLocalTodoList(serverTodoList) + }, latency) + }, [serverTodoList]) + + function handleChange(e) { + setInputValue(e.target.value) + } + + function handleSubmit(e) { + e.preventDefault() + if (inputValue === '') { + setDisplayErrorMessage(true) + setTimeout(() => { + setDisplayErrorMessage(false) + }, 3000) + + return + } + + let newTodo = { + id: uuidv4(), + text: inputValue, + } + + let newLocalTodoList = [...localTodoList, newTodo] + + setLocalTodoList(newLocalTodoList) + onSubmit(newTodo) + setInputValue('') + } + + function handleDelete(id) { + let filteredLocalTodoList = localTodoList.filter(todo => todo.id !== id) + setLocalTodoList(filteredLocalTodoList) + onDelete(id) + } + + return ( +
+

{!interactable ? 'Todo List (Client 2)' : 'Todo List (Client 1)'}

+ {displayErrorMessage ? ( +

Must enter a value

+ ) : ( + <> + )} +
+ + +
+
    + {localTodoList.map(todo => ( +
  • + {todo.text} + +
  • + ))} +
+
+ ) +} + +const divStyle = { + border: '40px solid', + borderImage: 'url(' + '/landing/Client-window2.svg' + ') 25 25', +} + +const deleteButtonStyle = { + backgroundColor: 'white', + border: 'none', + cursor: 'pointer', + textAlign: 'right', +} + +const addButtonStyle = { + backgroundColor: 'white', + border: 'none', + cursor: 'pointer', + verticalAlign: '-3px', +} + +const listStyle = { + listStyleType: 'none', + paddingLeft: '0px', +} + +const errorStyling = { + color: 'red', +} diff --git a/src/components/TodoList/icon_add.png b/src/components/TodoList/icon_add.png new file mode 100644 index 0000000000000000000000000000000000000000..18f6287e8af8827101224889d7563fa82f68c2e8 GIT binary patch literal 498 zcmVPx$tVu*cR5(wqQ$34RK@hAOSXWp>F)}eSQaBV*bmonLC+iOo3=9ku1K|uz`~_kl zA{fXe1_pwei3@iJ&YN-155z#Zz{o(e3uVz`*>3G)-|<}Vb z@+^Qe0QOCfTgoB;5k z*Xu0|27?X5ZW6>8cZ$dmzz)ltbN)D6+4S9B5qWHT=iKp>(pMv(_kNM&VO5gHS5^x+J!u5D z030l(oSH5BX9V`nd%q0eEkg)vB(K(WZGj)wuL!EDvV^yd;LBt(*)tptKZg+Rk?b}s zs%ol(BFaM@7WU odzGoVH+HNY~-6i@59LlhI0g%j_(e8 zKIh^qzlg&OD*ThypX113I49pwthdcgaAz7r=w0g%uTE|*Todm8;a+^0x8_v2l2lq+s^)N<5=)JL|fowN&|oAj!XNR TH + + diff --git a/src/components/TodoList/signalVertical.svg b/src/components/TodoList/signalVertical.svg new file mode 100644 index 0000000..6da99dd --- /dev/null +++ b/src/components/TodoList/signalVertical.svg @@ -0,0 +1,4 @@ + + + diff --git a/src/pages/case-study.mdx b/src/pages/case-study.mdx index faeafbf..b6c3e62 100644 --- a/src/pages/case-study.mdx +++ b/src/pages/case-study.mdx @@ -1,5 +1,8 @@ import Dia2ClientChangesSync from './diagrams/Dia2ClientChangesSync.jsx' import LatencySlider from '@site/src/components/LatencySlider/LatencySlider' +import TodoList from '@site/src/components/TodoList/TodoList' +import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' ## Overview @@ -34,24 +37,14 @@ Given this and the predominance of the client-server architecture in web apps, w On the surface, building real-time collaborative applications may not seem any different than building other web applications, however, if we break down each word of “real-time collaboration” into more concrete and technical definitions, we quickly realize that is not the case. -## Introduction - -## Purpose of the Study - -## Methodology - -### Data Collection - -### Analysis Techniques - -## Findings - -### Key Discoveries - -### Implications - -## Conclusion - -### Summary of Results - -### Future Directions + + + ``` Javascript console.log('hello') console.log('hello') ``` + + + ``` Javascript console.log('subscriptions'); console.log('subscriptions'); + ``` + + + +