Page MenuHomeSealhub

No OneTemporary

diff --git a/src/collection.ts b/src/collection.ts
index 513e09a..d0b21c2 100644
--- a/src/collection.ts
+++ b/src/collection.ts
@@ -1,172 +1,181 @@
import { useState, useEffect } from "./react-api/api";
import axios from "axios";
import EventEmitter from "eventemitter3";
import {
SealiousItem,
SealiousCollectionResponse,
CollectionParams,
ComplexFilterParam,
} from "./types";
import { CollectionItem } from "./item";
import url from "./url";
const DEFAULT_ITEMS_PER_PAGE = 10;
export function useCollection<
ItemFields,
ItemClass extends CollectionItem<ItemFields>,
TCollection extends CollectionClient<ItemFields, ItemClass>
>(
CollectionClass: CollectionClass<ItemFields, ItemClass, TCollection>,
params: CollectionParams<ItemFields>
-): [TCollection, ItemClass[], CollectionParams<ItemFields>] {
+): [TCollection, ItemClass[], CollectionParams<ItemFields>, number] {
const [collectionClient] = useState<TCollection>(
() => new CollectionClass(params)
);
+ const [version, setVersion] = useState(0);
const [items, setItems] = useState<ItemClass[]>([]);
useEffect(() => {
const callback = () =>
collectionClient
.refresh()
.then(() => setItems(collectionClient.items));
collectionClient.on("change", callback);
+ collectionClient.on("state-change", () => {
+ setVersion((v) => v + 1);
+ });
callback();
return () => {
collectionClient.removeListener("change", callback);
};
}, []);
- return [collectionClient, items, collectionClient.params];
+ return [collectionClient, items, collectionClient.params, version];
}
export type CollectionClass<
ItemFields,
Y extends CollectionItem<ItemFields>,
TCollection extends CollectionClient<ItemFields, Y>
> = new (params: CollectionParams<ItemFields>) => TCollection;
export default class CollectionClient<
ItemFields,
ItemClass extends CollectionItem<ItemFields>
> extends EventEmitter {
items: ItemClass[];
collection_name: string;
item_constructor: new (
id: string,
body: ItemFields & SealiousItem,
attachments?: { [id: string]: SealiousItem }
) => ItemClass;
params: CollectionParams<ItemFields>;
needs_saving: boolean = false;
has_next_page: boolean | null = null;
+ loading: boolean = false;
constructor(params: CollectionParams<ItemFields>) {
super();
this.params = params;
this.save = this.save.bind(this);
this.setPage = this.setPage.bind(this);
this.getPage = this.getPage.bind(this);
this.nextPage = this.nextPage.bind(this);
this.prevPage = this.prevPage.bind(this);
}
setFilter<Field extends keyof ItemFields>(
field_name: Field,
value: ComplexFilterParam<ItemFields[Field]> | ItemFields[Field],
replace: boolean = false
) {
if (!this.params.filter) {
this.params.filter = {};
}
if (replace) {
this.params.filter[field_name] = value;
} else {
if (typeof value == "object") {
this.params.filter[field_name] = {
...this.params.filter[field_name],
...value,
};
} else {
this.params.filter = {
...this.params.filter,
[field_name]: value,
};
}
}
this.emit("change");
}
isPaginated(): boolean {
return typeof this.params.pagination == "object";
}
setPage(page: number) {
if (!this.isPaginated()) {
throw new Error("This client does not use pagination");
}
this.params.pagination = {
items: this?.params?.pagination?.items || DEFAULT_ITEMS_PER_PAGE,
page: page,
};
this.emit("change");
}
getPage(): number {
if (!this.isPaginated()) {
throw new Error("This client does not use pagination");
}
return this.params?.pagination?.page || 1;
}
nextPage() {
if (this.has_next_page) {
this.setPage(this.getPage() + 1);
}
}
prevPage() {
if (this.getPage() > 0) {
this.setPage(this.getPage() - 1);
}
}
async refresh(): Promise<void> {
+ this.loading = true;
+ this.emit("state-change");
const response = (await axios.get(
url(`/api/v1/collections/${this.collection_name}`, this.params)
)) as { data: SealiousCollectionResponse<SealiousItem & ItemFields> };
this.needs_saving = false;
const attachments = response.data.attachments;
if (this.isPaginated()) {
this.has_next_page =
response.data.items.length === this.params?.pagination?.items;
}
this.items = response.data.items.map((item) => {
const entry = new this.item_constructor(item.id, item, attachments);
entry.on("change", () => this.emit("change"));
entry.on("temp-change", () => (this.needs_saving = true));
return entry;
});
+ this.loading = false;
+ this.emit("state-change");
}
async create(body: ItemFields) {
const response = await axios.post(
`/api/v1/collections/${this.collection_name}`,
body
);
this.emit("change");
return response.data.items;
}
async save() {
const promises = [];
for (const item of this.items) {
if (item.needs_saving) {
promises.push(item.save());
}
}
await Promise.all(promises);
this.needs_saving = false;
this.emit("change");
}
}
diff --git a/src/users.ts b/src/users.ts
index d3ad11a..00375a4 100644
--- a/src/users.ts
+++ b/src/users.ts
@@ -1,84 +1,84 @@
import axios from "axios";
import Collection, { useCollection } from "./collection";
import { useItem, CollectionItem } from "./item";
import {
SingleResourceParams,
SealiousUserRoleItem,
SealiousCollectionResponse,
SealiousItem,
} from "./types";
import url from "./url";
export function useUsers(
params: SingleResourceParams<typeof UserFields>
-): [Users, User[], SingleResourceParams<typeof UserFields>] {
+): [Users, User[], SingleResourceParams<typeof UserFields>, number] {
return useCollection<typeof UserFields, User, Users>(Users, params);
}
export function useUser(
id: string
): [boolean, typeof UserFields | undefined, User] {
return useItem<typeof UserFields, User>(User, id);
}
export const UserFields = {
username: "",
prefered_hours_per_day: 0,
email: "",
roles: [] as Array<string>,
};
export class User extends CollectionItem<typeof UserFields> {
getInfo() {
return {
collection_name: "users",
fields: UserFields,
writable_fields: [
"username",
"prefered_hours_per_day",
"email",
] as (keyof typeof UserFields)[],
fields_with_attachments: ["roles"] as (keyof typeof UserFields)[],
};
}
getRoles(): string[] {
const roles = this.temp_data.roles
.map((role_id: string) => this.getAttachment(role_id))
.map((role: SealiousUserRoleItem) => role.role);
return roles;
}
hasRole(role: string) {
return this.getRoles().includes(role);
}
async setRole(role: string) {
const {
data: { items: current_roles },
} = (await axios.get(
url(`/api/v1/collections/user-roles`, {
filter: { user: this.id },
})
)) as {
data: SealiousCollectionResponse<typeof UserFields & SealiousItem>;
};
for (const role_entry of current_roles) {
await axios.delete(
`/api/v1/collections/user-roles/${role_entry.id}`
);
}
await axios.post("/api/v1/collections/user-roles", {
role: role,
user: this.id,
});
await this.refresh();
}
}
export class Users extends Collection<typeof UserFields, User> {
collection_name = "users";
item_constructor = User;
}

File Metadata

Mime Type
text/x-diff
Expires
Sat, Oct 11, 07:20 (1 d, 1 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
983962
Default Alt Text
(7 KB)

Event Timeline