update global (texte + logo)
This commit is contained in:
41
Linkwarden/store/account.ts
Normal file
41
Linkwarden/store/account.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { create } from "zustand";
|
||||
import { AccountSettings } from "@/types/global";
|
||||
|
||||
type ResponseObject = {
|
||||
ok: boolean;
|
||||
data: Omit<AccountSettings, "password"> | object | string;
|
||||
};
|
||||
|
||||
type AccountStore = {
|
||||
account: AccountSettings;
|
||||
setAccount: (id: number) => void;
|
||||
updateAccount: (user: AccountSettings) => Promise<ResponseObject>;
|
||||
};
|
||||
|
||||
const useAccountStore = create<AccountStore>()((set) => ({
|
||||
account: {} as AccountSettings,
|
||||
setAccount: async (id) => {
|
||||
const response = await fetch(`/api/v1/users/${id}`);
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok) set({ account: { ...data.response } });
|
||||
},
|
||||
updateAccount: async (user) => {
|
||||
const response = await fetch(`/api/v1/users/${user.id}`, {
|
||||
method: "PUT",
|
||||
body: JSON.stringify(user),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok) set({ account: { ...data.response } });
|
||||
|
||||
return { ok: response.ok, data: data.response };
|
||||
},
|
||||
}));
|
||||
|
||||
export default useAccountStore;
|
94
Linkwarden/store/collections.ts
Normal file
94
Linkwarden/store/collections.ts
Normal file
@ -0,0 +1,94 @@
|
||||
import { create } from "zustand";
|
||||
import { CollectionIncludingMembersAndLinkCount } from "@/types/global";
|
||||
import useTagStore from "./tags";
|
||||
|
||||
type ResponseObject = {
|
||||
ok: boolean;
|
||||
data: object | string;
|
||||
};
|
||||
|
||||
type CollectionStore = {
|
||||
collections: CollectionIncludingMembersAndLinkCount[];
|
||||
setCollections: () => void;
|
||||
addCollection: (
|
||||
body: CollectionIncludingMembersAndLinkCount
|
||||
) => Promise<ResponseObject>;
|
||||
updateCollection: (
|
||||
collection: CollectionIncludingMembersAndLinkCount
|
||||
) => Promise<ResponseObject>;
|
||||
removeCollection: (collectionId: number) => Promise<ResponseObject>;
|
||||
};
|
||||
|
||||
const useCollectionStore = create<CollectionStore>()((set) => ({
|
||||
collections: [],
|
||||
setCollections: async () => {
|
||||
const response = await fetch("/api/v1/collections");
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok) set({ collections: data.response });
|
||||
},
|
||||
addCollection: async (body) => {
|
||||
const response = await fetch("/api/v1/collections", {
|
||||
body: JSON.stringify(body),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
method: "POST",
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok)
|
||||
set((state) => ({
|
||||
collections: [...state.collections, data.response],
|
||||
}));
|
||||
|
||||
return { ok: response.ok, data: data.response };
|
||||
},
|
||||
updateCollection: async (collection) => {
|
||||
const response = await fetch(`/api/v1/collections/${collection.id}`, {
|
||||
body: JSON.stringify(collection),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
method: "PUT",
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok)
|
||||
set((state) => ({
|
||||
collections: state.collections.map((e) =>
|
||||
e.id === data.response.id ? data.response : e
|
||||
),
|
||||
}));
|
||||
|
||||
return { ok: response.ok, data: data.response };
|
||||
},
|
||||
removeCollection: async (collectionId) => {
|
||||
const response = await fetch(`/api/v1/collections/${collectionId}`, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
method: "DELETE",
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
set((state) => ({
|
||||
collections: state.collections.filter(
|
||||
(collection) =>
|
||||
collection.id !== collectionId &&
|
||||
collection.parentId !== collectionId
|
||||
),
|
||||
}));
|
||||
useTagStore.getState().setTags();
|
||||
}
|
||||
|
||||
return { ok: response.ok, data: data.response };
|
||||
},
|
||||
}));
|
||||
|
||||
export default useCollectionStore;
|
217
Linkwarden/store/links.ts
Normal file
217
Linkwarden/store/links.ts
Normal file
@ -0,0 +1,217 @@
|
||||
import { create } from "zustand";
|
||||
import { LinkIncludingShortenedCollectionAndTags } from "@/types/global";
|
||||
import useTagStore from "./tags";
|
||||
import useCollectionStore from "./collections";
|
||||
|
||||
type ResponseObject = {
|
||||
ok: boolean;
|
||||
data: object | string;
|
||||
};
|
||||
|
||||
type LinkStore = {
|
||||
links: LinkIncludingShortenedCollectionAndTags[];
|
||||
selectedLinks: LinkIncludingShortenedCollectionAndTags[];
|
||||
setLinks: (
|
||||
data: LinkIncludingShortenedCollectionAndTags[],
|
||||
isInitialCall: boolean
|
||||
) => void;
|
||||
setSelectedLinks: (links: LinkIncludingShortenedCollectionAndTags[]) => void;
|
||||
addLink: (
|
||||
body: LinkIncludingShortenedCollectionAndTags
|
||||
) => Promise<ResponseObject>;
|
||||
getLink: (linkId: number, publicRoute?: boolean) => Promise<ResponseObject>;
|
||||
updateLink: (
|
||||
link: LinkIncludingShortenedCollectionAndTags
|
||||
) => Promise<ResponseObject>;
|
||||
updateLinks: (
|
||||
links: LinkIncludingShortenedCollectionAndTags[],
|
||||
removePreviousTags: boolean,
|
||||
newData: Pick<
|
||||
LinkIncludingShortenedCollectionAndTags,
|
||||
"tags" | "collectionId"
|
||||
>
|
||||
) => Promise<ResponseObject>;
|
||||
removeLink: (linkId: number) => Promise<ResponseObject>;
|
||||
deleteLinksById: (linkIds: number[]) => Promise<ResponseObject>;
|
||||
resetLinks: () => void;
|
||||
};
|
||||
|
||||
const useLinkStore = create<LinkStore>()((set) => ({
|
||||
links: [],
|
||||
selectedLinks: [],
|
||||
setLinks: async (data, isInitialCall) => {
|
||||
isInitialCall &&
|
||||
set(() => ({
|
||||
links: [],
|
||||
}));
|
||||
set((state) => ({
|
||||
// Filter duplicate links by id
|
||||
links: [...state.links, ...data].reduce(
|
||||
(links: LinkIncludingShortenedCollectionAndTags[], item) => {
|
||||
if (!links.some((link) => link.id === item.id)) {
|
||||
links.push(item);
|
||||
}
|
||||
return links;
|
||||
},
|
||||
[]
|
||||
),
|
||||
}));
|
||||
},
|
||||
setSelectedLinks: (links) => set({ selectedLinks: links }),
|
||||
addLink: async (body) => {
|
||||
const response = await fetch("/api/v1/links", {
|
||||
body: JSON.stringify(body),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
method: "POST",
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
set((state) => ({
|
||||
links: [data.response, ...state.links],
|
||||
}));
|
||||
useTagStore.getState().setTags();
|
||||
useCollectionStore.getState().setCollections();
|
||||
}
|
||||
|
||||
return { ok: response.ok, data: data.response };
|
||||
},
|
||||
getLink: async (linkId, publicRoute) => {
|
||||
const path = publicRoute
|
||||
? `/api/v1/public/links/${linkId}`
|
||||
: `/api/v1/links/${linkId}`;
|
||||
|
||||
const response = await fetch(path);
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
set((state) => {
|
||||
const linkExists = state.links.some(
|
||||
(link) => link.id === data.response.id
|
||||
);
|
||||
|
||||
if (linkExists) {
|
||||
return {
|
||||
links: state.links.map((e) =>
|
||||
e.id === data.response.id ? data.response : e
|
||||
),
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
links: [...state.links, data.response],
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
return { ok: response.ok, data: data.response };
|
||||
},
|
||||
updateLink: async (link) => {
|
||||
const response = await fetch(`/api/v1/links/${link.id}`, {
|
||||
body: JSON.stringify(link),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
method: "PUT",
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
set((state) => ({
|
||||
links: state.links.map((e) =>
|
||||
e.id === data.response.id ? data.response : e
|
||||
),
|
||||
}));
|
||||
useTagStore.getState().setTags();
|
||||
useCollectionStore.getState().setCollections();
|
||||
}
|
||||
|
||||
return { ok: response.ok, data: data.response };
|
||||
},
|
||||
updateLinks: async (links, removePreviousTags, newData) => {
|
||||
const response = await fetch("/api/v1/links", {
|
||||
body: JSON.stringify({ links, removePreviousTags, newData }),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
method: "PUT",
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
set((state) => ({
|
||||
links: state.links.map((e) =>
|
||||
links.some((link) => link.id === e.id)
|
||||
? {
|
||||
...e,
|
||||
collectionId: newData.collectionId ?? e.collectionId,
|
||||
collection: {
|
||||
...e.collection,
|
||||
id: newData.collectionId ?? e.collection.id,
|
||||
},
|
||||
tags: removePreviousTags
|
||||
? [...(newData.tags ?? [])]
|
||||
: [...e.tags, ...(newData.tags ?? [])],
|
||||
}
|
||||
: e
|
||||
),
|
||||
}));
|
||||
useTagStore.getState().setTags();
|
||||
useCollectionStore.getState().setCollections();
|
||||
}
|
||||
|
||||
return { ok: response.ok, data: data.response };
|
||||
},
|
||||
removeLink: async (linkId) => {
|
||||
const response = await fetch(`/api/v1/links/${linkId}`, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
method: "DELETE",
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
set((state) => ({
|
||||
links: state.links.filter((e) => e.id !== linkId),
|
||||
}));
|
||||
useTagStore.getState().setTags();
|
||||
useCollectionStore.getState().setCollections();
|
||||
}
|
||||
|
||||
return { ok: response.ok, data: data.response };
|
||||
},
|
||||
deleteLinksById: async (linkIds: number[]) => {
|
||||
const response = await fetch("/api/v1/links", {
|
||||
body: JSON.stringify({ linkIds }),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
method: "DELETE",
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
set((state) => ({
|
||||
links: state.links.filter((e) => !linkIds.includes(e.id as number)),
|
||||
}));
|
||||
useTagStore.getState().setTags();
|
||||
useCollectionStore.getState().setCollections();
|
||||
}
|
||||
|
||||
return { ok: response.ok, data: data.response };
|
||||
},
|
||||
resetLinks: () => set({ links: [] }),
|
||||
}));
|
||||
|
||||
export default useLinkStore;
|
57
Linkwarden/store/localSettings.ts
Normal file
57
Linkwarden/store/localSettings.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import { create } from "zustand";
|
||||
|
||||
type LocalSettings = {
|
||||
theme?: string;
|
||||
viewMode?: string;
|
||||
};
|
||||
|
||||
type LocalSettingsStore = {
|
||||
settings: LocalSettings;
|
||||
updateSettings: (settings: LocalSettings) => void;
|
||||
setSettings: () => void;
|
||||
};
|
||||
|
||||
const useLocalSettingsStore = create<LocalSettingsStore>((set) => ({
|
||||
settings: {
|
||||
theme: "",
|
||||
viewMode: "",
|
||||
},
|
||||
updateSettings: async (newSettings) => {
|
||||
if (
|
||||
newSettings.theme &&
|
||||
newSettings.theme !== localStorage.getItem("theme")
|
||||
) {
|
||||
localStorage.setItem("theme", newSettings.theme);
|
||||
|
||||
const localTheme = localStorage.getItem("theme") || "";
|
||||
|
||||
document.querySelector("html")?.setAttribute("data-theme", localTheme);
|
||||
}
|
||||
|
||||
if (
|
||||
newSettings.viewMode &&
|
||||
newSettings.viewMode !== localStorage.getItem("viewMode")
|
||||
) {
|
||||
localStorage.setItem("viewMode", newSettings.viewMode);
|
||||
|
||||
// const localTheme = localStorage.getItem("viewMode") || "";
|
||||
}
|
||||
|
||||
set((state) => ({ settings: { ...state.settings, ...newSettings } }));
|
||||
},
|
||||
setSettings: async () => {
|
||||
if (!localStorage.getItem("theme")) {
|
||||
localStorage.setItem("theme", "dark");
|
||||
}
|
||||
|
||||
const localTheme = localStorage.getItem("theme") || "";
|
||||
|
||||
set((state) => ({
|
||||
settings: { ...state.settings, theme: localTheme },
|
||||
}));
|
||||
|
||||
document.querySelector("html")?.setAttribute("data-theme", localTheme);
|
||||
},
|
||||
}));
|
||||
|
||||
export default useLocalSettingsStore;
|
64
Linkwarden/store/modals.ts
Normal file
64
Linkwarden/store/modals.ts
Normal file
@ -0,0 +1,64 @@
|
||||
import {
|
||||
CollectionIncludingMembersAndLinkCount,
|
||||
LinkIncludingShortenedCollectionAndTags,
|
||||
} from "@/types/global";
|
||||
import { create } from "zustand";
|
||||
|
||||
type Modal =
|
||||
| {
|
||||
modal: "LINK";
|
||||
state: boolean;
|
||||
method: "CREATE";
|
||||
active?: LinkIncludingShortenedCollectionAndTags;
|
||||
}
|
||||
| {
|
||||
modal: "LINK";
|
||||
state: boolean;
|
||||
method: "UPDATE";
|
||||
active: LinkIncludingShortenedCollectionAndTags;
|
||||
}
|
||||
| {
|
||||
modal: "LINK";
|
||||
state: boolean;
|
||||
method: "FORMATS";
|
||||
active: LinkIncludingShortenedCollectionAndTags;
|
||||
}
|
||||
| {
|
||||
modal: "COLLECTION";
|
||||
state: boolean;
|
||||
method: "UPDATE";
|
||||
isOwner: boolean;
|
||||
active: CollectionIncludingMembersAndLinkCount;
|
||||
defaultIndex?: number;
|
||||
}
|
||||
| {
|
||||
modal: "COLLECTION";
|
||||
state: boolean;
|
||||
method: "CREATE";
|
||||
isOwner?: boolean;
|
||||
active?: CollectionIncludingMembersAndLinkCount;
|
||||
defaultIndex?: number;
|
||||
}
|
||||
| {
|
||||
modal: "COLLECTION";
|
||||
state: boolean;
|
||||
method: "VIEW_TEAM";
|
||||
isOwner?: boolean;
|
||||
active?: CollectionIncludingMembersAndLinkCount;
|
||||
defaultIndex?: number;
|
||||
}
|
||||
| null;
|
||||
|
||||
type ModalsStore = {
|
||||
modal: Modal;
|
||||
setModal: (modal: Modal) => void;
|
||||
};
|
||||
|
||||
const useModalStore = create<ModalsStore>((set) => ({
|
||||
modal: null,
|
||||
setModal: (modal: Modal) => {
|
||||
set({ modal });
|
||||
},
|
||||
}));
|
||||
|
||||
export default useModalStore;
|
62
Linkwarden/store/tags.ts
Normal file
62
Linkwarden/store/tags.ts
Normal file
@ -0,0 +1,62 @@
|
||||
import { create } from "zustand";
|
||||
import { TagIncludingLinkCount } from "@/types/global";
|
||||
|
||||
type ResponseObject = {
|
||||
ok: boolean;
|
||||
data: object | string;
|
||||
};
|
||||
|
||||
type TagStore = {
|
||||
tags: TagIncludingLinkCount[];
|
||||
setTags: () => void;
|
||||
updateTag: (tag: TagIncludingLinkCount) => Promise<ResponseObject>;
|
||||
removeTag: (tagId: number) => Promise<ResponseObject>;
|
||||
};
|
||||
|
||||
const useTagStore = create<TagStore>()((set) => ({
|
||||
tags: [],
|
||||
setTags: async () => {
|
||||
const response = await fetch("/api/v1/tags");
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok) set({ tags: data.response });
|
||||
},
|
||||
updateTag: async (tag) => {
|
||||
const response = await fetch(`/api/v1/tags/${tag.id}`, {
|
||||
body: JSON.stringify(tag),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
method: "PUT",
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
set((state) => ({
|
||||
tags: state.tags.map((e) =>
|
||||
e.id === data.response.id ? data.response : e
|
||||
),
|
||||
}));
|
||||
}
|
||||
|
||||
return { ok: response.ok, data: data.response };
|
||||
},
|
||||
removeTag: async (tagId) => {
|
||||
const response = await fetch(`/api/v1/tags/${tagId}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
set((state) => ({
|
||||
tags: state.tags.filter((e) => e.id !== tagId),
|
||||
}));
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return { ok: response.ok, data: data.response };
|
||||
},
|
||||
}));
|
||||
|
||||
export default useTagStore;
|
56
Linkwarden/store/tokens.ts
Normal file
56
Linkwarden/store/tokens.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import { AccessToken } from "@prisma/client";
|
||||
import { create } from "zustand";
|
||||
|
||||
// Token store
|
||||
|
||||
type ResponseObject = {
|
||||
ok: boolean;
|
||||
data: object | string;
|
||||
};
|
||||
|
||||
type TokenStore = {
|
||||
tokens: Partial<AccessToken>[];
|
||||
setTokens: (data: Partial<AccessToken>[]) => void;
|
||||
addToken: (body: Partial<AccessToken>[]) => Promise<ResponseObject>;
|
||||
revokeToken: (tokenId: number) => Promise<ResponseObject>;
|
||||
};
|
||||
|
||||
const useTokenStore = create<TokenStore>((set) => ({
|
||||
tokens: [],
|
||||
setTokens: async (data) => {
|
||||
set(() => ({
|
||||
tokens: data,
|
||||
}));
|
||||
},
|
||||
addToken: async (body) => {
|
||||
const response = await fetch("/api/v1/tokens", {
|
||||
body: JSON.stringify(body),
|
||||
method: "POST",
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok)
|
||||
set((state) => ({
|
||||
tokens: [...state.tokens, data.response.token],
|
||||
}));
|
||||
|
||||
return { ok: response.ok, data: data.response };
|
||||
},
|
||||
revokeToken: async (tokenId) => {
|
||||
const response = await fetch(`/api/v1/tokens/${tokenId}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok)
|
||||
set((state) => ({
|
||||
tokens: state.tokens.filter((token) => token.id !== tokenId),
|
||||
}));
|
||||
|
||||
return { ok: response.ok, data: data.response };
|
||||
},
|
||||
}));
|
||||
|
||||
export default useTokenStore;
|
Reference in New Issue
Block a user