Skip to content
This repository has been archived by the owner on Apr 17, 2023. It is now read-only.

Commit

Permalink
Merge pull request #1072 from Arenukvern/feat/vue3-hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
wtrocki authored Mar 19, 2021
2 parents f47ddec + 42f9c5d commit db71e2b
Show file tree
Hide file tree
Showing 46 changed files with 1,604 additions and 190 deletions.
102 changes: 102 additions & 0 deletions examples/vue-datastore/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# vue-datastore

## Project setup

```
yarn install
```

### Compiles and hot-reloads for development

```
yarn serve
```

### Compiles and minifies for production

```
yarn build
```

### Lints and fixes files

```
yarn lint
```

### Customize configuration

See [Configuration Reference](https://cli.vuejs.org/config/).

# Offix - Vue3 Todo Example App

This example demonstrates how to get started using Offix in a Vue project. The app is a simple
todo app making use of the `offix-client` and can be used as launch pad to getting started
with Offix and make use of the features in the library.

## Getting started

To get started, run:

```
yarn install
```

### Setting up a server

For simplicity, a GraphQL Serve in-memory server has been provided. You can make changes to the GrapQL schema, by editing the `models/runtime.graphql` file. To start the server, run the following
command:

```
yarn startServer
```

Alternatively, you can implement your own backend server.

### Starting the client

Next, configure the GraphQL server address in the `src/clientConfig.js` file:

```
...
const wsLink = new WebSocketLink({
uri: 'ws://<YOUR-SERVER-ADDRESS-HERE>',
...
});
const httpLink = new HttpLink({
uri: 'http://<YOUR-SERVER-ADDRESS-HERE>',
});
...
```

### Starting the client

Lastly, run the following commands from the React example folder.

```
yarn start
```

## Adding more models

1. Edit runtime.graphql file in `src/model/runtime.graphql`
2. Generate models yarn generate
3. Review new models

## Running as native capacitor application

yarn build
yarn cap add ios
yarn cap copy ios
yarn cap open ios

yarn build
yarn cap add android
// Swap main activity https://github.com/capacitor-community/sqlite
yarn cap copy android
yarn cap open android
13 changes: 13 additions & 0 deletions examples/vue-datastore/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
49 changes: 49 additions & 0 deletions examples/vue-datastore/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"name": "vue-datastore",
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"serve": "vite preview",
"upgrade-next": "yarn yarn-upgrade-all add vue@next ant-design-vue@next",
"generate": "offix generate --schema ./src/model/runtime.graphql --outputPath ./src/datastore/generated",
"startServer": "gqlserve serve --datasync --conflict=clientSideWins --port=5400 ./src/model/runtime.graphql",
"linkdatastore": "cd ../../packages/datastore/datastore && yarn link && cd - && yarn link offix-datastore && rm -Rf ./node_modules/react && && rm -Rf ./node_modules/react-dom",
"linkdatastorecli": "cd ../../packages/datastore/cli && yarn link && cd - && yarn link @offix/cli"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"dependencies": {
"@ant-design/colors": "^6.0.0",
"ant-design-vue": "^2.0.1",
"offix-datastore": "^0.4.0",
"vue": "^3.0.6",
"@ant-design/icons-vue": "^6.0.1"
},
"devDependencies": {
"@offix/cli": "^0.3.3",
"@types/node": "^14.14.31",
"@vitejs/plugin-vue": "^1.1.4",
"@vitejs/plugin-vue-jsx": "^1.1.2",
"@vue/compiler-sfc": "^3.0.5",
"babel-plugin-import": "^1.13.3",
"eslint": "^7.21.0",
"eslint-plugin-vue": "^7.6.0",
"graphback-cli": "^1.1.2",
"graphql-serve": "1.1.2",
"sass": "^1.32.8",
"typescript": "^4.2.2",
"vite": "^2.0.4",
"yarn-upgrade-all": "^0.5.4"
}
}
Binary file added examples/vue-datastore/public/favicon.ico
Binary file not shown.
93 changes: 93 additions & 0 deletions examples/vue-datastore/src/App.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<template>
<Loading v-if="loading" />
<Error v-else-if="error" :message="error.message" />
<div :style="containerStyle" v-else>
<div style="width: 60%">
<a-page-header
:title="isNotToAddView ? 'Offix Todo' : 'Add Todo'"
@back="isNotToAddView ? null : (isToAddView = false)"
>
<template v-slot:extra v-if="isNotToAddView">
<a-button type="primary" @click="isToAddView = true" ghost>
Add Todo
</a-button>
<a-button type="primary" danger ghost>
{{ replicating ? "Online" : "Offline" }}
</a-button>
</template>
<TodoList v-if="isNotToAddView" :todos="data" />
<AddTodo v-else :cancel="cancelAddTodo" />
</a-page-header>
</div>
</div>
</template>
<script lang="ts">
import { NetworkStatusEvent } from "offix-datastore/types/replication/network/NetworkStatus";
import { computed, defineComponent, onMounted, ref, toRefs, watch } from "vue";
import { Error, TodoList } from "./components";
import { datastore } from "./datastore/config";
import { useFindTodos } from "./datastore/hooks";
import Loading from "./components/UI/Loading.vue";
import AddTodo from "./components/forms/AddTodo.vue";
export default defineComponent({
name: "App",
components: {
AddTodo,
Error,
Loading,
TodoList,
},
setup() {
const containerStyle = {
display: "flex",
alignItems: "start",
justifyContent: "center",
minHeight: "100vh",
width: "100vw",
padding: "2em 0",
};
const replicating = ref(false);
const isToAddView = ref(false);
const isNotToAddView = computed(() => !isToAddView.value);
const { state, subscribeToUpdates } = useFindTodos();
const { loading, data, error } = toRefs(state.value);
console.log({ loading, data, error, state });
const startReplication = () => {
datastore.startReplication();
replicating.value = true;
};
onMounted(() => {
startReplication();
datastore.getNetworkIndicator()?.subscribe({
next: (event: NetworkStatusEvent) => {
if (event.isOnline) {
startReplication();
} else {
datastore.stopReplication();
replicating.value = false;
}
},
});
});
watch(
data,
() => {
const subscription = subscribeToUpdates();
return () => subscription.unsubscribe();
},
{ deep: true, immediate: true }
);
const cancelAddTodo = () => (isToAddView.value = false);
return {
containerStyle,
isToAddView,
isNotToAddView,
loading,
replicating,
error,
data,
cancelAddTodo,
};
},
});
</script>
57 changes: 57 additions & 0 deletions examples/vue-datastore/src/components/Todo/TodoItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { DeleteOutlined, EditOutlined } from "@ant-design/icons-vue";
import { defineComponent, h, ref } from "@vue/runtime-core";
import { PropType } from "vue";
import { useDeleteTodo } from "../../datastore/hooks";
import EditTodo from "../forms/EditTodo.vue";
import ToggleTodo from "../forms/ToggleTodo.vue";
import { Todo } from "/@/datastore/generated";
export const TodoItem = defineComponent({
props: {
todo: {
type: Object as PropType<Todo>,
required: true,
},
},
components: {
ToggleTodo,
EditTodo,
},
setup(props) {
const { remove: deleteTodo } = useDeleteTodo();
const edit = ref(false);
const handleDelete = () => {
deleteTodo({ _id: props.todo._id })
.then((res) => console.log("response", res))
.catch((error: any) => console.log(error));
};

return () =>
h(
edit.value ? (
<edit-todo
todo={props.todo}
toggleEdit={() => (edit.value = !edit.value)}
/>
) : (
<a-row justify="space-between">
<a-col>
<toggle-todo todo={props.todo} />
<p>
<b>Description: </b>
<br />
{props.todo.description}
</p>
</a-col>
<a-col>
<a-button type="primary" onClick={() => (edit.value = true)}>
<EditOutlined />
</a-button>
<a-button type="primary" onClick={handleDelete} danger>
<DeleteOutlined />
</a-button>
</a-col>
</a-row>
)
);
},
});
32 changes: 32 additions & 0 deletions examples/vue-datastore/src/components/Todo/TodoList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { computed, defineComponent, h, PropType } from "vue";
import { Todo } from "../../datastore/generated";
import { Empty } from "../UI";
import { TodoItem } from "./TodoItem";

export const TodoList = defineComponent({
props: {
todos: {
type: Array as PropType<Todo[]>,
required: true,
default: () => [],
},
},
components: {
TodoItem,
Empty,
},
setup(props) {
const noTodos = computed(() => !props.todos || props.todos.length === 0);
return () =>
h("div", {}, [
noTodos.value ? h(<empty />) : null,
...props.todos.map((todo) =>
h(
<a-card key={todo._id} style='margin: "0.5em 0"'>
<todo-item todo={todo} />
</a-card>
)
),
]);
},
});
2 changes: 2 additions & 0 deletions examples/vue-datastore/src/components/Todo/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./TodoItem";
export * from "./TodoList";
17 changes: 17 additions & 0 deletions examples/vue-datastore/src/components/UI/Empty.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//@ts-nocheck //FIXME: remove ignore
import { defineComponent, h } from "@vue/runtime-core";

export const Empty = defineComponent({
setup() {
return () =>
h(
<div class="empty" style={{ background: "#fff" }}>
<div class="empty-icon">
<i class="icon icon-3x icon-flag" />
</div>
<p class="empty-title h5">You have no todo items</p>
<p class="empty-subtitle">Click the button to create a new task</p>
</div>
);
}
});
22 changes: 22 additions & 0 deletions examples/vue-datastore/src/components/UI/Error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { defineComponent, h } from "vue";

export const Error = defineComponent({
name: "Error",
props: {
message: {
type: String,
required: false,
default: "",
},
},
setup(props) {
return () =>
h(
<a-result
status="error"
title="Oops, it looks like there was an error!"
subTitle={props.message}
/>
);
},
});
Loading

0 comments on commit db71e2b

Please sign in to comment.