Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update dozer library #128

Merged
merged 9 commits into from
Nov 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions usecases/api-auth/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ cd ..

3. Generate a master token for auth by running the command from the project root directory where `dozer-config.yaml` is located:
```bash
dozer api generate-token
dozer security generate-token
```

4. Copy the `MASTER_TOKEN` generated from the previous step and export the `MASTER_TOKEN` as an environment variable
Expand All @@ -33,7 +33,7 @@ export MASTER_TOKEN=your_token_here
5. Start the Dozer app. Dozer will start running, handling the data operations and APIs authorization as defined in your configuration. To do this, simply run the command:

```bash
dozer
dozer run
```

6. Open the new terminal and change the directory to the `server` folder and install required package dependencies:
Expand Down
4 changes: 2 additions & 2 deletions usecases/api-auth/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@dozerjs/dozer": "^0.0.10",
"@dozerjs/dozer-react": "^0.0.8",
"@emotion/react": "^11.10.5",
"@emotion/styled": "^11.10.5",
"@dozerjs/dozer": "0.0.6",
"@dozerjs/dozer-react": "0.0.4",
"@mui/material": "^5.11.7",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
Expand Down
Binary file modified usecases/api-auth/client/public/favicon.ico
Binary file not shown.
1 change: 1 addition & 0 deletions usecases/api-auth/client/public/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion usecases/api-auth/client/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ function App() {
return (
<div className="App">
<header className="App-header">
<img src="https://getdozer.io/img/logo.svg" className="App-logo" alt="logo" />
<img src="/logo.svg" className="App-logo" alt="logo" />
<BrowserRouter>
<Routes>
<Route element={<Login />} path={"/admin"} />
Expand Down
103 changes: 33 additions & 70 deletions usecases/api-auth/client/src/components/admin/dashboard.js
Original file line number Diff line number Diff line change
@@ -1,75 +1,23 @@
import {useEffect, useState} from "react";
import {Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow} from "@mui/material";

import {useOnEvent, useQueryCommon} from "@dozerjs/dozer-react";
import {OperationType} from "@dozerjs/dozer/lib/esm/generated/protos/types";
import {useNavigate} from "react-router-dom";
import { Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from "@mui/material";
import { DozerProvider, useDozerEvent, useDozerQuery } from "@dozerjs/dozer-react";
import { Navigate } from "react-router-dom";

function pad(num, size) {
num = num.toString();
while (num.length < size) num = "0" + num;
return num;
}

function Dashboard() {
const navigate = useNavigate();
const token = localStorage.getItem('token');
if (!token) {
navigate("/admin");
}
const [values, setValues] = useState([]);
const query = { limit: 500000};
const { records: events } = useQueryCommon("movies_with_bookings", query, token);

useOnEvent('movies_with_bookings', (data, _1, primaryIndexKeys, mapper) => {
setValues(recs => {
if (data.getTyp() === OperationType.UPDATE) {
let oldValue = mapper.mapRecord(data.getOld().getValuesList());
let existingIndex = recs.findIndex(v => primaryIndexKeys.every(k => v[k] === oldValue[k]))

if (existingIndex > -1) {
recs[existingIndex] = mapper.mapRecord(data.getNew().getValuesList());

return [...recs]
}
}

if (data.getTyp() === OperationType.INSERT) {
console.log('insert');
return [...recs, mapper.mapRecord(data.getNew().getValuesList())]
}

if (data.getTyp() === OperationType.DELETE && data.getNew()) {
console.log('delete');
let oldValue = mapper.mapRecord(data.getNew().getValuesList());
let existingIndex = recs.findIndex(v => primaryIndexKeys.every(k => {
return v[k] === oldValue[k]
}))

if (existingIndex > -1) {
recs.splice(existingIndex, 1);
return [...recs]
}
}

return recs;
});
}, token);

function DataTable() {
const query = { limit: 500000 };
const { records, connect } = useDozerQuery("movies_with_bookings", query);
const { stream } = useDozerEvent([{ endpoint: 'movies_with_bookings' }]);
connect(stream);

useEffect(() => {
if(values.length === 0) {
setValues(events);
}
}, [events])


if (values.length === 0) {
if (records.length === 0) {
return null;
}

return <div>
<h3>Admin dashboard</h3>
return (
<TableContainer component={Paper}>
<Table sx={{ minWidth: 650 }} aria-label="simple table">
<TableHead>
Expand All @@ -80,20 +28,35 @@ function Dashboard() {
</TableRow>
</TableHead>
<TableBody>
{ values.map(f => (
{records.map(f => (
<TableRow
key={ f.id }
sx={ { '&:last-child td, &:last-child th': { border: 0 } } }
key={f.id}
sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
>
<TableCell component="th" scope="row">{ f.id }</TableCell>
<TableCell>{ f.name }</TableCell>
<TableCell align="center">{ f.count }</TableCell>
<TableCell component="th" scope="row">{f.id}</TableCell>
<TableCell>{f.name}</TableCell>
<TableCell align="center">{f.count}</TableCell>
</TableRow>
)) }
))}
</TableBody>
</Table>
</TableContainer>
</div>;
)
}

function Dashboard() {
const token = localStorage.getItem('token');
if (!token) {
return <Navigate to="/admin" />
}


return <DozerProvider value={{
authToken: token,
}}>
<h3>Admin dashboard</h3>
<DataTable />
</DozerProvider>;
}

export default Dashboard;
9 changes: 7 additions & 2 deletions usecases/api-auth/client/src/components/public/movies.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {useEffect, useState} from "react";
import { useEffect, useState } from "react";
import { DozerProvider } from '@dozerjs/dozer-react';
import MoviesList from "./moviesList";

function Movies() {
Expand Down Expand Up @@ -34,7 +35,11 @@ function Movies() {
return null;
}

return <MoviesList token={token} />;
return <DozerProvider value={{
authToken: token,
}}>
<MoviesList token={token} />
</DozerProvider>
}

export default Movies;
134 changes: 77 additions & 57 deletions usecases/api-auth/client/src/components/public/moviesList.js
Original file line number Diff line number Diff line change
@@ -1,53 +1,45 @@
import {useEffect, useState} from "react";
import {ApiClient} from "@dozerjs/dozer";
import {Button, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow} from "@mui/material";
import {useOnEvent} from "@dozerjs/dozer-react";
import {OperationType} from "@dozerjs/dozer/lib/esm/generated/protos/types";
import { useCallback, useEffect, useState } from "react";
import { useDozerEvent, useDozerQuery } from "@dozerjs/dozer-react";
import { Button, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from "@mui/material";
import { OperationType } from "@dozerjs/dozer/lib/esm/generated/protos/types";
import { types_pb } from "@dozerjs/dozer";
import { RecordMapper } from "@dozerjs/dozer/lib/esm/helper";

function MoviesList({ token }) {
let [movies, setMovies] = useState([]);
let [tickets, setTickets] = useState({});
let [user, setUser] = useState({});

useEffect(() => {
if (token) {
let client = new ApiClient("only_movies", {authToken: token});
client.query().then(response => {
setMovies(response[1]);
});

let bookings_client = new ApiClient("user_bookings", {authToken: token});
bookings_client.query().then(response => {
let r = {};
console.log(response);
response[1].forEach(value => {
r[value.movie_id] = value;
})
setTickets(r);
});

let users_client = new ApiClient("users", {authToken: token});
users_client.query().then(response => {
setUser(response[1][0]);
});
}
}, [token]);
const { records: movies } = useDozerQuery("only_movies");
const { records: userBookingsRecords, fields: userBookingsFields } = useDozerQuery("user_bookings");
const { records: usersRecords, fields: usersFields } = useDozerQuery("users");
const { stream } = useDozerEvent([
{
endpoint: 'user_bookings',
eventType: types_pb.EventType.ALL,
},
{
endpoint: 'users',
eventType: types_pb.EventType.ALL,
},
]);

useOnEvent('user_bookings', (data, _1, primaryIndexKeys, mapper) => {
const handleUserBookingsEvent = useCallback((data) => {
if (userBookingsFields.length) {
const mapper = new RecordMapper(userBookingsFields);
setTickets(recs => {
if (data.getTyp() === OperationType.UPDATE) {
let recNew = mapper.mapRecord(data.getNew().getValuesList());
let recOld = mapper.mapRecord(data.getOld().getValuesList());
let recNew = mapper.mapRecord(data.getNew());
let recOld = mapper.mapRecord(data.getOld());

return {
...recs,
[recOld.movie_id]: {...recOld},
[recNew.movie_id]: {...recNew}
[recOld.movie_id]: { ...recOld },
[recNew.movie_id]: { ...recNew }
};
}

if (data.getTyp() === OperationType.INSERT) {
let recNew = mapper.mapRecord(data.getNew().getValuesList());
let recNew = mapper.mapRecord(data.getNew());

return {
[recNew.movie_id]: recNew,
Expand All @@ -56,7 +48,7 @@ function MoviesList({ token }) {
}

if (data.getTyp() === OperationType.DELETE && data.getNew()) {
let recOld = mapper.mapRecord(data.getNew().getValuesList());
let recOld = mapper.mapRecord(data.getNew());
return {
[recOld.movie_id]: null,
...recs
Expand All @@ -65,23 +57,51 @@ function MoviesList({ token }) {

return recs;
});
},
token)
}
}, [userBookingsFields]);

useOnEvent('users', (data, _1, primaryIndexKeys, mapper) => {
setUser(recs => {
if (data.getTyp() === OperationType.UPDATE || data.getTyp() === OperationType.INSERT) {
return mapper.mapRecord(data.getNew().getValuesList());
}
const handleUsersEvent = useCallback((data) => {
const mapper = new RecordMapper(usersFields);
setUser(recs => {
if (data.getTyp() === OperationType.UPDATE || data.getTyp() === OperationType.INSERT) {
return mapper.mapRecord(data.getNew());
}

if (data.getTyp() === OperationType.DELETE && data.getNew()) {
return null;
}
if (data.getTyp() === OperationType.DELETE && data.getNew()) {
return null;
}

return recs;
});
}, [usersFields]);

useEffect(() => {
const r = {};
userBookingsRecords.forEach(value => {
r[value.movie_id] = value;
})
setTickets(r);
}, [userBookingsRecords])

useEffect(() => {
setUser(usersRecords[0]);
}, [usersRecords])

useEffect(() => {
const cb = (operation) => {
if (operation.getEndpointName() === 'user_bookings') {
handleUserBookingsEvent(operation);
}
if (operation.getEndpointName() === 'users') {
handleUsersEvent(operation);
}
}
stream?.on('data', cb);
return () => {
stream?.removeListener(cb);
}
}, [stream, handleUserBookingsEvent, handleUsersEvent])

return recs;
});
},
token)
const buyTicket = (id) => {
fetch('http://localhost:4000/public/book_movie', {
method: 'POST',
Expand Down Expand Up @@ -119,19 +139,19 @@ function MoviesList({ token }) {
</TableRow>
</TableHead>
<TableBody>
{ movies.map(f => (
{movies.map(f => (
<TableRow
key={ f.id }
sx={ { '&:last-child td, &:last-child th': { border: 0 } } }
key={f.id}
sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
>
<TableCell component="th" scope="row">{ f.id }</TableCell>
<TableCell>{ f.name }</TableCell>
<TableCell align={"center"}>{ tickets[f.id]?.count ?? 0 }</TableCell>
<TableCell component="th" scope="row">{f.id}</TableCell>
<TableCell>{f.name}</TableCell>
<TableCell align={"center"}>{tickets[f.id]?.count ?? 0}</TableCell>
<TableCell>
<Button onClick={() => buyTicket(f.id)} variant="contained" color="primary">Buy ticket</Button>
</TableCell>
</TableRow>
)) }
))}
</TableBody>
</Table>
</TableContainer>
Expand Down
Loading
Loading