Skip to content

Commit

Permalink
feat (case-study):
Browse files Browse the repository at this point in the history
Added interactive todo list component

Co-authored-by: Alex Sklar <[email protected]>
Co-authored-by: Franco Waisfeld <[email protected]>
Co-authored-by: Joseph Liang <[email protected]>
  • Loading branch information
4 people committed Apr 19, 2024
1 parent fc66659 commit 25cc4b6
Show file tree
Hide file tree
Showing 9 changed files with 248 additions and 26 deletions.
21 changes: 17 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
77 changes: 77 additions & 0 deletions src/components/TodoList/TodoList.js
Original file line number Diff line number Diff line change
@@ -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 (
<div className="grid grid-cols-1 gap-0 justify-center">
<TodoListClient
serverTodoList={todoList}
onSubmit={handleSubmit}
onDelete={handleDelete}
latency={0}
interactable={true}
narrow={true}
client={1}
/>
<SignalVertical />
<TodoListClient
serverTodoList={todoList}
onSubmit={handleSubmit}
onDelete={handleDelete}
latency={1000}
interactable={false}
narrow={true}
client={2}
/>
</div>
)
}

return (
<div className="flex">
<TodoListClient
serverTodoList={todoList}
onSubmit={handleSubmit}
onDelete={handleDelete}
latency={0}
interactable={true}
narrow={false}
/>
<Signal />
<TodoListClient
serverTodoList={todoList}
onSubmit={handleSubmit}
onDelete={handleDelete}
latency={1000}
interactable={false}
narrow={false}
/>
</div>
)
}
130 changes: 130 additions & 0 deletions src/components/TodoList/TodoListClient.js
Original file line number Diff line number Diff line change
@@ -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 (
<div
className={
narrow
? 'container inline-block w-[300px] m-0 p-0 min-h-80'
: 'container inline-block w-[400px] m-0 p-0 min-h-80'
}
style={
!interactable
? { ...divStyle, pointerEvents: 'none', opacity: '.5' }
: divStyle
}
>
<h3>{!interactable ? 'Todo List (Client 2)' : 'Todo List (Client 1)'}</h3>
{displayErrorMessage ? (
<p style={errorStyling}>Must enter a value</p>
) : (
<></>
)}
<form>
<input
type="text"
placeholder="Enter new todo"
value={inputValue}
onChange={handleChange}
/>
<button style={addButtonStyle} onClick={handleSubmit}>
<img src={addIcon} />
</button>
</form>
<ul style={listStyle}>
{localTodoList.map(todo => (
<li key={todo.id}>
{todo.text}
<button
style={deleteButtonStyle}
onClick={() => handleDelete(todo.id)}
>
<img src={deleteIcon} />
</button>
</li>
))}
</ul>
</div>
)
}

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',
}
Binary file added src/components/TodoList/icon_add.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/components/TodoList/icon_delete.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/components/TodoList/signal.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/components/TodoList/signalVertical.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
35 changes: 14 additions & 21 deletions src/pages/case-study.mdx
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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
<Tabs>
<TabItem value="mutators" label="mutators.js">
``` Javascript console.log('hello') console.log('hello') ```
</TabItem>
<TabItem value="subscriptions" label="subscriptions.js">
``` Javascript console.log('subscriptions'); console.log('subscriptions');
```
</TabItem>
</Tabs>

<TodoList />

0 comments on commit 25cc4b6

Please sign in to comment.