Skip to content

Commit 3342eb3

Browse files
committed
feat: use postgres transport
2 parents 2118281 + 03c4070 commit 3342eb3

12 files changed

+288
-24
lines changed

README.md

+101-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,111 @@
1+
# Lists App Backend 📡
2+
3+
Welcome to the backend repository of the Lists app, powered by [React Server](https://state-less.cloud)!
4+
5+
![Lists App Frontend](https://github.com/C5H8NNaO4/lists-app-frontend/raw/master/public/screenshot.png)
6+
7+
## Overview
8+
9+
The Lists app backend provides the robust server-side functionality needed to support the [Lists app](https://lists.state-less.cloud)'s seamless user experience. Built on the React Server framework, this backend code enables real-time synchronization, data storage, and interaction with the frontend.
10+
11+
## Key Features
12+
13+
- **Real-Time Sync**: Achieve real-time updates and synchronization across clients.
14+
- **Data Storage**: Efficiently store task lists, reminders, and user data.
15+
- **Server-Rendered**: Utilize server-rendering capabilities for enhanced performance.
16+
- **Scalable Architecture**: Build a scalable backend for handling multiple users.
17+
- **Clean Codebase**: Based on the clean-starter repo for a structured foundation.
18+
19+
## Getting Started
20+
### Installation
21+
#### Install the backend
22+
```
23+
git clone https://github.com/C5H8NNaO4/lists-app-backend.git
24+
cd lists-app-backend
25+
yarn install
26+
yarn start
27+
```
28+
#### Install the frontend
29+
```
30+
git clone https://github.com/C5H8NNaO4/lists-app-frontend.git
31+
cd lists-app-frontend
32+
yarn install
33+
yarn dev
34+
```
35+
36+
## Contribute
37+
* Fork the repository
38+
* Create a branch
39+
* Commit your changes
40+
* Push to the branch
41+
* Open a pull request
42+
43+
We welcome contributions from the community! Feel free to submit bug reports, feature requests, or pull requests to help make Lists even better.
44+
## Learn More About React Server
45+
46+
Explore the power of [React Server](https://state-less.cloud), the framework used to develop this backend. With React Server, you can build reactive, server-rendered applications with ease.
47+
48+
## License
49+
50+
This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details.
51+
52+
Empower Your Lists App with a Robust Backend 🚀
53+
154
# React Server
255

356
![npm (scoped)](https://img.shields.io/npm/v/@state-less/react-server)
457

558
The @state-less/clean-starter repository is designed to provide a starting point for developers exploring React Server. It includes essential backend components, utilities, and examples that illustrate the fundamental concepts and capabilities of React Server.
659

60+
# React Server
761
React Server allows the creation of server-side React components using TSX, promoting a component-driven architecture for building robust and maintainable backend solutions. By using @state-less/clean-starter, developers can quickly get started with this innovative approach to full-stack development.
862

63+
```tsx
64+
import { Scopes, useState, clientKey } from '@state-less/react-server';
65+
import { ServerSideProps } from './ServerSideProps';
66+
67+
export const HelloWorldExample2 = (props, { key, context }) => {
68+
// The useState hook looks familiar?
69+
const [count, setState] = useState(0, {
70+
key: "count",
71+
scope: Scopes.Global,
72+
});
73+
74+
// A simple function that can be executed from the client side.
75+
const increase = () => {
76+
setState(count + 1);
77+
};
78+
79+
return (
80+
// Simply pass down props to the client side.
81+
<ServerSideProps
82+
key={clientKey(`${key}-props`, context)}
83+
count={count}
84+
increase={increase}
85+
/>
86+
);
87+
};
88+
```
89+
90+
Use the familiar approach of React to build serverside applications in a declarative way. React has proven to be a successful framework for building large scale applications while keeping a clean state-management solution to provide reactive realtime enabled modern UIs. React favors a clean codebase due to its inherently modular structure and component driven approach. React allows you to cleanly abstract the complexity of modern applications using *states*, *hooks* and *components*.
91+
92+
React Server brings the same flexibility to the server side by giving you a Framework that handles TSX compilation, a small React engine that powers *hooks*, *states* and the lifecycle of *components*. It also abstracts data storage and data transportation into a common concept of *states*. Data is stored in *Stores* which can be accessed by components using *hooks* (`useState`). The `useState` hook provides reactivity and automatically re-renders the component when its value is updated using the setter. Data is transported by consuming server-side states / components on the clientside using the `useComponent` hook. We are using *GraphQL* as transportation layer to provide a robust foundation.
93+
94+
Developers familiar with **React** and JSX components `<Component hello="world" />` are able to jump right into developing full-stack applications. It really works well and provides a seamless reactive experience on both the backend and the frontend. States are synchronized to all connected clients using PUB / SUB.
95+
996
For detailed documentation and in-depth guides, please visit the official website at [state-less.cloud](https://state-less.cloud).
1097

98+
## Explore Examples
99+
Dive into real-world examples, like the [Lists App](https://lists.state-less.cloud), showcasing the potential of React Server.
100+
101+
## Key Features
102+
103+
- **Server-Side React**: Create server-side React components using TSX for efficient, component-driven backend development.
104+
- **@state-less/clean-starter**: Jumpstart your project with essential backend components, utilities, and examples.
105+
- **Explore the Future**: Harness the power of server-side real-time TSX components.
106+
107+
For comprehensive documentation and detailed guides, visit the official [state-less.cloud](https://state-less.cloud) website.
108+
11109
## Getting Started
12110

13111
### Backend
@@ -122,4 +220,6 @@ _Note: You can still override the provided client if you pass one in the options
122220

123221
That's it, your App is now powered by the same backend as the documentation under [state-less.cloud](https://state-less.cloud).
124222

125-
Happy Hacking!
223+
---------
224+
225+
**License**: This project is under the **MIT License** - see the [LICENSE.md](/LICENSE.txt) file for details.

dist/components/Lists.js

+57-6
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ var Todo = function Todo(_ref3, _ref4) {
8181
dueDate = _ref3$dueDate === void 0 ? null : _ref3$dueDate,
8282
_ref3$dueTime = _ref3.dueTime,
8383
dueTime = _ref3$dueTime === void 0 ? null : _ref3$dueTime,
84+
note = _ref3.note,
8485
_changeType = _ref3.changeType,
8586
createdAt = _ref3.createdAt,
8687
color = _ref3.color;
@@ -108,6 +109,7 @@ var Todo = function Todo(_ref3, _ref4) {
108109
valuePoints: valuePoints,
109110
creditedValuePoints: creditedValuePoints,
110111
negativePoints: negativePoints,
112+
note: note,
111113
dueDate: dueDate,
112114
dueTime: dueTime,
113115
type: 'Todo',
@@ -180,6 +182,14 @@ var Todo = function Todo(_ref3, _ref4) {
180182
reset: 1000 * 60 * 60 * reset
181183
}));
182184
};
185+
var setNote = function setNote(note) {
186+
if (typeof note !== 'string' || note.length > 32000) {
187+
throw new Error('Invalid note');
188+
}
189+
setTodo(_objectSpread(_objectSpread({}, todo), {}, {
190+
note: note
191+
}));
192+
};
183193
var setValuePoints = function setValuePoints(valuePoints) {
184194
if (typeof valuePoints !== 'number' && valuePoints < 0 || valuePoints > 100) {
185195
throw new Error('Invalid value points');
@@ -226,6 +236,7 @@ var Todo = function Todo(_ref3, _ref4) {
226236
setTitle: setTitle,
227237
setDueDate: setDueDate,
228238
setDueTime: setDueTime,
239+
setNote: setNote,
229240
type: "Todo",
230241
createdAt: createdAt,
231242
lastModified: todo.lastModified,
@@ -332,10 +343,20 @@ var Counter = function Counter(_ref5, _ref6) {
332343
archived: Date.now()
333344
}));
334345
};
346+
var setTitle = function setTitle(title) {
347+
if (typeof title !== 'string') {
348+
throw new Error('Invalid title');
349+
}
350+
setCounter(_objectSpread(_objectSpread({}, counter), {}, {
351+
title: title,
352+
lastModified: Date.now()
353+
}));
354+
};
335355
return (0, _jsxRuntime.jsx)(_ServerSideProps.ServerSideProps, _objectSpread(_objectSpread({}, counter), {}, {
336356
archive: archive,
337357
increase: increase,
338358
decrease: decrease,
359+
setTitle: setTitle,
339360
changeType: function changeType(type) {
340361
return _changeType2(id, type);
341362
},
@@ -401,12 +422,22 @@ var Expense = function Expense(_ref7, _ref8) {
401422
lastModified: Date.now()
402423
}));
403424
};
425+
var setTitle = function setTitle(title) {
426+
if (typeof title !== 'string') {
427+
throw new Error('Invalid title');
428+
}
429+
setExpense(_objectSpread(_objectSpread({}, expense), {}, {
430+
title: title,
431+
lastModified: Date.now()
432+
}));
433+
};
404434
return (0, _jsxRuntime.jsx)(_ServerSideProps.ServerSideProps, _objectSpread(_objectSpread({}, expense), {}, {
405435
archive: archive,
406436
changeType: function changeType(type) {
407437
return _changeType3(id, type);
408438
},
409439
setValue: setValue,
440+
setTitle: setTitle,
410441
type: "Expense"
411442
}), (0, _reactServer.clientKey)("".concat(id, "-expense"), context));
412443
};
@@ -521,15 +552,20 @@ var List = function List(_ref9, _ref10) {
521552
throw new Error('Invalid item');
522553
}
523554
setTodos([].concat((0, _toConsumableArray2["default"])(todos), [newItem]));
555+
<<<<<<< HEAD
524556
setOrder([todoId].concat((0, _toConsumableArray2["default"])(order)));
525557
points.setValue(points.value + 1);
558+
=======
559+
setOrder([].concat((0, _toConsumableArray2["default"])(order), [todoId]));
560+
points.value += 1;
561+
>>>>>>> 03c407037195270bc170ca100fdfb6f491246104
526562
return newItem;
527563
};
528564
var removeEntry = function removeEntry(todoId) {
529565
var _user16, _todo$value, _todo$value2;
530566
var store = _reactServer.Dispatcher.getCurrent().getStore();
531567
var todo = store.getState(null, {
532-
key: "todo-".concat(todoId),
568+
key: "todo",
533569
scope: "".concat(todoId, ".").concat(((_user16 = user) === null || _user16 === void 0 ? void 0 : _user16.id) || _reactServer.Scopes.Client)
534570
});
535571
setOrder(order.filter(function (id) {
@@ -538,7 +574,12 @@ var List = function List(_ref9, _ref10) {
538574
setTodos(todos.filter(function (todo) {
539575
return todo.id !== todoId;
540576
}));
577+
<<<<<<< HEAD
541578
points.setValue(points.value - 1 - (todo !== null && todo !== void 0 && (_todo$value = todo.value) !== null && _todo$value !== void 0 && _todo$value.archived ? 1 : 0) - ((todo === null || todo === void 0 ? void 0 : (_todo$value2 = todo.value) === null || _todo$value2 === void 0 ? void 0 : _todo$value2.valuePoints) || 0));
579+
=======
580+
points.value = points.value - 1 - (todo !== null && todo !== void 0 && (_todo$value = todo.value) !== null && _todo$value !== void 0 && _todo$value.archived ? 1 : 0) - ((todo === null || todo === void 0 ? void 0 : (_todo$value2 = todo.value) === null || _todo$value2 === void 0 ? void 0 : _todo$value2.valuePoints) || 0);
581+
return todo.value;
582+
>>>>>>> 03c407037195270bc170ca100fdfb6f491246104
542583
};
543584
var addLabel = function addLabel(label) {
544585
var labelId = (0, _uuid.v4)();
@@ -705,6 +746,10 @@ var exportData = function exportData(_ref11) {
705746
key: 'color',
706747
scope: "".concat("list-".concat(list.id), ".", (user === null || user === void 0 ? void 0 : user.id) || clientId)
707748
});
749+
var title = store.getState(null, {
750+
key: 'title',
751+
scope: "".concat("list-".concat(list.id), ".", (user === null || user === void 0 ? void 0 : user.id) || clientId)
752+
});
708753
var settings = store.getState(null, {
709754
key: 'settings',
710755
scope: "".concat("list-".concat(list.id), ".", (user === null || user === void 0 ? void 0 : user.id) || clientId)
@@ -717,6 +762,7 @@ var exportData = function exportData(_ref11) {
717762
Object.assign(todo, stored.value);
718763
});
719764
data[list.id] = _objectSpread(_objectSpread({}, list), {}, {
765+
title: title.value,
720766
color: color.value,
721767
order: order.value,
722768
todos: todos.value,
@@ -766,9 +812,10 @@ var MyLists = function MyLists(_, _ref12) {
766812
order = state.order;
767813
var addEntry = function addEntry(list) {
768814
var id = (0, _uuid.v4)();
769-
var newList = _objectSpread(_objectSpread({}, list), {}, {
815+
var newList = _objectSpread(_objectSpread({
816+
id: id
817+
}, list), {}, {
770818
order: [],
771-
id: id,
772819
settings: {
773820
defaultValuePoints: DEFAULT_VALUE_POINTS,
774821
defaultType: 'Todo',
@@ -778,11 +825,14 @@ var MyLists = function MyLists(_, _ref12) {
778825
});
779826
var newLists = [newList].concat((0, _toConsumableArray2["default"])(state.lists));
780827
setState({
781-
order: [id].concat((0, _toConsumableArray2["default"])(state.order)),
828+
order: [newList.id].concat((0, _toConsumableArray2["default"])(state.order)),
782829
lists: newLists
783830
});
784831
};
785832
var removeEntry = function removeEntry(id) {
833+
var removed = state.lists.find(function (list) {
834+
return list.id === id;
835+
});
786836
setState({
787837
lists: state.lists.filter(function (list) {
788838
return list.id !== id;
@@ -791,6 +841,7 @@ var MyLists = function MyLists(_, _ref12) {
791841
return listId !== id;
792842
})
793843
});
844+
return removed;
794845
};
795846
var exportUserData = function exportUserData() {
796847
return exportData({
@@ -861,7 +912,7 @@ var MyLists = function MyLists(_, _ref12) {
861912
};
862913
exports.MyLists = MyLists;
863914
var isValidTodo = function isValidTodo(todo) {
864-
return todo.id && todo.title && 'completed' in todo;
915+
return todo.id && 'completed' in todo;
865916
};
866917
var isValidCounter = function isValidCounter(counter) {
867918
return counter.id && 'count' in counter && counter.type === 'Counter';
@@ -873,7 +924,7 @@ var isValidLabel = function isValidLabel(label) {
873924
return label.id && label.title && Object.keys(label).length === 2;
874925
};
875926
var isValidList = function isValidList(list) {
876-
return list.id && list.title && list.todos && list.order && list.order.every(function (id) {
927+
return list.id && list.todos && list.order && list.order.every(function (id) {
877928
return typeof id === 'string';
878929
}) && list.todos.every(function (todo) {
879930
return isValidItem(todo);

dist/components/examples.js

+10
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,15 @@ var HelloWorldExample1 = function HelloWorldExample1(props, _ref) {
2929
}, (0, _reactServer.clientKey)('hello-world-1-props', context));
3030
};
3131
exports.HelloWorldExample1 = HelloWorldExample1;
32+
<<<<<<< HEAD
3233
var HelloWorldExample2 = function HelloWorldExample2(_props, _ref2) {
3334
var key = _ref2.key,
3435
context = _ref2.context;
36+
=======
37+
var HelloWorldExample2 = function HelloWorldExample2(props, _ref) {
38+
var key = _ref.key,
39+
context = _ref.context;
40+
>>>>>>> 03c407037195270bc170ca100fdfb6f491246104
3541
var _useState3 = (0, _reactServer.useState)(0, {
3642
key: 'count',
3743
scope: _reactServer.Scopes.Global
@@ -45,6 +51,10 @@ var HelloWorldExample2 = function HelloWorldExample2(_props, _ref2) {
4551
return (0, _jsxRuntime.jsx)(_ServerSideProps.ServerSideProps, {
4652
count: count,
4753
increase: increase
54+
<<<<<<< HEAD
4855
}, (0, _reactServer.clientKey)('hello-world-2-props', context));
56+
=======
57+
}, (0, _reactServer.clientKey)("".concat(key, "-props"), context));
58+
>>>>>>> 03c407037195270bc170ca100fdfb6f491246104
4959
};
5060
exports.HelloWorldExample2 = HelloWorldExample2;

dist/index.js

+12-1
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,21 @@ var landingList2 = {
119119
}],
120120
order: ['counter-0']
121121
};
122+
var demoList1 = {
123+
id: 'demo-list-1',
124+
title: 'Todos',
125+
order: ['todo-0'],
126+
todos: [{
127+
id: 'todo-0',
128+
title: 'Todo',
129+
type: 'Todo',
130+
completed: false
131+
}]
132+
};
122133
var reactServer = (0, _jsxRuntime.jsxs)(_reactServer.Server, {
123134
children: [(0, _jsxRuntime.jsx)(_ChatRoom.ChatApp, {}, "chat"), (0, _jsxRuntime.jsx)(_ViewCounter.ViewCounter, {}, "view-counter"), (0, _jsxRuntime.jsx)(_Features.Features, {}, "features"), (0, _jsxRuntime.jsx)(_reactServer.TestComponent, {}, "test"), (0, _jsxRuntime.jsx)(_Navigation.Navigation, {}, "navigation"), (0, _jsxRuntime.jsx)(_examples.HelloWorldExample1, {}, "hello-world-1"), (0, _jsxRuntime.jsx)(_examples.HelloWorldExample2, {}, "hello-world-2"), (0, _jsxRuntime.jsx)(_Pages.Pages, {}, "pages"), (0, _jsxRuntime.jsx)(_Pages.DynamicPage, {}, "page"), (0, _jsxRuntime.jsx)(_Lists.MyLists, {}, "my-lists"), (0, _jsxRuntime.jsx)(_Lists.MyListsMeta, {}, "my-lists-points"), (0, _jsxRuntime.jsx)(_Votings.Votings, {
124135
policies: [_Votings.VotingPolicies.SingleVote]
125-
}, "votings"), (0, _jsxRuntime.jsx)(_Lists.List, _objectSpread({}, landingList1), "landing-list-1"), (0, _jsxRuntime.jsx)(_Lists.List, _objectSpread({}, landingList2), "landing-list-2"), (0, _jsxRuntime.jsx)(_Votings.Votings, {
136+
}, "votings"), (0, _jsxRuntime.jsx)(_Lists.List, _objectSpread({}, landingList1), "landing-list-1"), (0, _jsxRuntime.jsx)(_Lists.List, _objectSpread({}, landingList2), "landing-list-2"), (0, _jsxRuntime.jsx)(_Lists.List, _objectSpread({}, demoList1), "todos"), (0, _jsxRuntime.jsx)(_Votings.Votings, {
126137
policies: []
127138
}, "votings-multiple"), (0, _jsxRuntime.jsx)(_Session.Session, {}, "session"), (0, _jsxRuntime.jsx)(_Poll.Poll, {
128139
values: ['Where can I get this?', 'Meh...', 'Shut up and take my money.'],

0 commit comments

Comments
 (0)