Skip to content

Commit

Permalink
docs: to-do-list example 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
chungheon_yi committed Nov 22, 2024
1 parent 1a63ed3 commit f5dc84f
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 9 deletions.
10 changes: 3 additions & 7 deletions apps/core/src/models/NamespaceStore.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { deepClone } from '../utils'
import EventPublisher from './EventPublisher'
import { Listener } from './type'
import { createStateProxy } from './utils/createStateProxy'
Expand All @@ -12,20 +13,15 @@ export default class NamespaceStore<State extends Record<string | symbol, any>>

private publisher: EventPublisher<State>

protected deepClone(value: any) {
// @ts-ignore
return global.structuredClone ? structuredClone?.(value) : JSON.parse(JSON.stringify(value))
}

constructor(initialState: State) {
this.initState = this.deepClone(initialState)
this.initState = deepClone(initialState)

this.publisher = new EventPublisher<State>()
this.state = createStateProxy(initialState, this.publisher)
}

reset() {
const deepCopiedState = this.deepClone(this.initState)
const deepCopiedState = deepClone(this.initState)

Object.keys(deepCopiedState).forEach((key) => {
this.state[key as keyof State] = deepCopiedState[key]
Expand Down
4 changes: 4 additions & 0 deletions apps/core/src/utils/deepClone.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export function deepClone(value: any) {
// @ts-ignore
return global.structuredClone ? structuredClone?.(value) : JSON.parse(JSON.stringify(value))
}
1 change: 1 addition & 0 deletions apps/core/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './deepClone'
export * from './ProxyWrapper'
2 changes: 0 additions & 2 deletions apps/docs/stories/scope/createContextScope.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@ const { Provider: DialogProvider, useNamespaceStores: useDialogNamespaceStore }
localStore: () => new Counter(),
})



const [createAlertDialogProvider, createAlertDialogScope] = createNamespaceScope('AlertDialog', [createDialogScope])

const { Provider: AlertDialogProvider, useNamespaceStores: useAlertDialogNamespaceStore } = createAlertDialogProvider(
Expand Down
49 changes: 49 additions & 0 deletions apps/docs/stories/scope/to-do-list/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React, { useState } from 'react'

import { createTodoScope, TodoProvider } from './scope'
import TodoList from './ToDoList'

const user1Scope = createTodoScope()
const user2Scope = createTodoScope()
const user3Scope = createTodoScope()

const App = () => {
const [activeUserId, setActiveUserId] = useState<'user1' | 'user2' | 'user3'>('user1')
const todoScopes = {
user1: user1Scope({}),
user2: user2Scope({}),
user3: user3Scope({}),
} as const

const handleUserChange = (userId: 'user1' | 'user2' | 'user3') => {
setActiveUserId(userId)
}

const scope = todoScopes?.[activeUserId]?.__scopeTodoList

return (
<div>
<h1>Multi-User To-Do List</h1>
<div>
<button type="button" onClick={() => handleUserChange('user1')}>
Switch to User 1
</button>
<button type="button" onClick={() => handleUserChange('user2')}>
Switch to User 2
</button>
<button type="button" onClick={() => handleUserChange('user3')}>
Switch to User 3
</button>
</div>
<TodoProvider scope={todoScopes.user1?.__scopeTodoList}>
<TodoProvider scope={todoScopes.user2?.__scopeTodoList}>
<TodoProvider scope={todoScopes.user3?.__scopeTodoList}>
<TodoList scope={scope} />
</TodoProvider>
</TodoProvider>
</TodoProvider>
</div>
)
}

export default App
16 changes: 16 additions & 0 deletions apps/docs/stories/scope/to-do-list/To-do-List.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import App from './App'

/* eslint-disable max-classes-per-file */

const meta = {
title: 'scope/to-do-list',

parameters: {},
argTypes: {},
}

export default meta

export const Example = () => {
return <App />
}
53 changes: 53 additions & 0 deletions apps/docs/stories/scope/to-do-list/ToDoList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Scope } from '@lodado/react-namespace'
import React, { useState } from 'react'

import { useTodoNamespaceStore } from './scope'

interface UserTodoListProps {
scope: Scope<any>
}

const TodoList: React.FC<UserTodoListProps> = ({ scope }) => {
const { user, todos, addTodo, toggleTodo, removeTodo } = useTodoNamespaceStore(
(state) => ({ user: state.user, todos: state.todos }),
scope,
)
const [newTodo, setNewTodo] = useState('')

const handleAddTodo = () => {
if (newTodo.trim() !== '') {
addTodo(newTodo.trim())
setNewTodo('')
}
}

return (
<div>
<h2>{user} To-Do List</h2>
<input type="text" value={newTodo} onChange={(e) => setNewTodo(e.target.value)} placeholder="Add a new task..." />
<button type="button" onClick={handleAddTodo}>
Add
</button>
<ul>
{todos.map((todo) => (
<li key={todo.id} style={{ display: 'flex', alignItems: 'center' }}>
<input type="checkbox" checked={todo.completed} onChange={() => toggleTodo(todo.id)} />
<span
style={{
textDecoration: todo.completed ? 'line-through' : 'none',
marginLeft: '8px',
}}
>
{todo.title}
</span>
<button type="button" onClick={() => removeTodo(todo.id)} style={{ marginLeft: 'auto', color: 'red' }}>
Remove
</button>
</li>
))}
</ul>
</div>
)
}

export default TodoList
12 changes: 12 additions & 0 deletions apps/docs/stories/scope/to-do-list/scope.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { createNamespaceScope } from '@lodado/react-namespace'

import TodoStore from './toDoStore'

export const [createTodoContext, createTodoScope] = createNamespaceScope('TodoList')

export const { Provider: TodoProvider, useNamespaceStores: useTodoNamespaceStore } = createTodoContext<TodoStore>(
'TodoList',
{
localStore: () => new TodoStore(),
},
)
38 changes: 38 additions & 0 deletions apps/docs/stories/scope/to-do-list/toDoStore.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { NamespaceStore } from '@lodado/namespace-core'

export interface Todo {
id: number
title: string
completed: boolean
}

export interface TodoState {
todos: Todo[]
user: string
}

let index = 0

export default class TodoStore extends NamespaceStore<TodoState> {
constructor() {
index += 1
super({ user: `user${index}}`, todos: [] })
}

addTodo(title: string) {
const newTodo: Todo = {
id: Date.now(),
title,
completed: false,
}
this.state.todos = [...this.state.todos, newTodo]
}

toggleTodo(id: number) {
this.state.todos = this.state.todos.map((todo) => (todo.id === id ? { ...todo, completed: !todo.completed } : todo))
}

removeTodo(id: number) {
this.state.todos = this.state.todos.filter((todo) => todo.id !== id)
}
}

0 comments on commit f5dc84f

Please sign in to comment.