|
import {createContext} from "@/utils/context"; |
|
import {generateUUID} from "@/utils/uuids"; |
|
import {getCurrentTimeIso8601} from "@/utils/dates"; |
|
import {useContext} from "preact/hooks"; |
|
import {Settings} from "@/contexts/settings"; |
|
import {feedPosts, feedTopic} from "@/utils/model"; |
|
import {LogAction} from "@/contexts/log"; |
|
|
|
export type Post = { |
|
user: string; |
|
date: string; |
|
generationDate: string | null; |
|
content: string; |
|
} |
|
|
|
export type Topic = { |
|
id: string; |
|
title: string; |
|
posts: Post[]; |
|
} |
|
|
|
export type TopicsContext = { |
|
generation: "done" | "pending" | "error"; |
|
import: "done" | "error"; |
|
topics: Topic[]; |
|
} |
|
|
|
const itemKey = "topics"; |
|
|
|
export const topicsCtx = createContext({ |
|
initialValue: () => { |
|
const storedTopics = localStorage.getItem(itemKey); |
|
return { |
|
generation: "done", |
|
import: "done", |
|
topics: storedTopics ? JSON.parse(storedTopics) as Topic[] : [] |
|
} as TopicsContext; |
|
}, |
|
controllers: (topicsContext: TopicsContext, setTopicsContext) => ({ |
|
effect: () => { |
|
|
|
localStorage.setItem(itemKey, JSON.stringify(topicsContext.topics)); |
|
}, |
|
actions: { |
|
reset: (): void => { |
|
setTopicsContext({ |
|
generation: "done", |
|
import: "done", |
|
topics: [] |
|
}); |
|
}, |
|
addTopic: (user: string, title: string, text: string): string => { |
|
const id = generateUUID(); |
|
setTopicsContext({ |
|
...topicsContext, |
|
topics: [...topicsContext.topics, { |
|
id: id, |
|
title, |
|
posts: [{ |
|
user: user, |
|
date: getCurrentTimeIso8601(), |
|
generationDate: null, |
|
content: text, |
|
}] |
|
}], |
|
}); |
|
return id; |
|
}, |
|
deleteTopic: (topicId: string): void => { |
|
setTopicsContext({ |
|
...topicsContext, |
|
topics: topicsContext.topics.filter((topic) => topic.id !== topicId) |
|
}); |
|
}, |
|
addPost: (topicId: string, user: string, text: string): void => { |
|
const newPost: Post = { |
|
user: user, |
|
date: getCurrentTimeIso8601(), |
|
generationDate: null, |
|
content: text, |
|
} |
|
setTopicsContext({ |
|
...topicsContext, |
|
topics: topicsContext.topics.map((topic) => topic.id === topicId ? { |
|
...topic, |
|
posts: [...topic.posts, newPost] |
|
} : topic) |
|
}); |
|
}, |
|
deletePost: (topicId: string, postIndex: number): void => { |
|
setTopicsContext({ |
|
...topicsContext, |
|
topics: topicsContext.topics.map((topic) => { |
|
if (topic.id !== topicId) { |
|
return topic; |
|
} |
|
|
|
|
|
const posts: Post[] = postIndex === 0 ? [] : topic.posts.filter((_, index) => index !== postIndex); |
|
|
|
return { |
|
...topic, |
|
posts |
|
}; |
|
|
|
}).filter((t) => t.posts.length > 0) |
|
}); |
|
}, |
|
generateTopic: async (settings: Settings, log: LogAction) => { |
|
const id = generateUUID(); |
|
setTopicsContext({ |
|
...topicsContext, |
|
generation: "pending", |
|
}); |
|
log(`Topic: ${id} -> generation start.`) |
|
feedTopic(settings, log, id, (topic: Topic) => { |
|
if(topic.title.length < 1) return; |
|
|
|
setTopicsContext((topicsContext: TopicsContext) => { |
|
|
|
const topicIndex = topicsContext.topics.findIndex((topic) => topic.id === id); |
|
|
|
|
|
if(topicIndex < 0) { |
|
return { |
|
...topicsContext, |
|
generation: "pending", |
|
topics: [...topicsContext.topics, topic] |
|
} satisfies TopicsContext |
|
} |
|
|
|
return { |
|
...topicsContext, |
|
generation: "pending", |
|
|
|
topics: topicsContext.topics.map(oldTopic => oldTopic.id === id ? topic : oldTopic), |
|
} satisfies TopicsContext |
|
}); |
|
|
|
}).then(() => { |
|
|
|
|
|
setTopicsContext((topicsContext: TopicsContext) => ({ |
|
...topicsContext, |
|
generation: "done", |
|
})) |
|
log(`Topic: ${id} -> generation done.`) |
|
}).catch((e: Error) => { |
|
setTopicsContext((topicsContext: TopicsContext) => ({ |
|
...topicsContext, |
|
generation: "error", |
|
})) |
|
log(`Topic: ${id} -> generation error (${e.message}).`) |
|
}); |
|
}, |
|
generatePosts: async (settings: Settings, log: LogAction, initialTopic: Topic) => { |
|
setTopicsContext({ |
|
...topicsContext, |
|
generation: "pending", |
|
}); |
|
log(`Topic: ${initialTopic.id} -> generation start.`) |
|
feedPosts(settings, log, initialTopic, (topic: Topic) => { |
|
setTopicsContext((topicsContext: TopicsContext) => { |
|
|
|
const topicIndex = topicsContext.topics.findIndex((topic) => topic.id === initialTopic.id); |
|
|
|
|
|
if(topicIndex < 0) { |
|
return { |
|
...topicsContext, |
|
generation: "pending", |
|
topics: [...topicsContext.topics, topic] |
|
} satisfies TopicsContext |
|
} |
|
|
|
return { |
|
...topicsContext, |
|
generation: "pending", |
|
|
|
topics: topicsContext.topics.map(oldTopic => oldTopic.id === initialTopic.id ? topic : oldTopic), |
|
} satisfies TopicsContext |
|
}); |
|
}).then(() => { |
|
setTopicsContext((topicsContext: TopicsContext) => ({ |
|
...topicsContext, |
|
generation: "done", |
|
})) |
|
log(`Topic: ${initialTopic.id} -> generation done.`) |
|
}).catch((e: Error) => { |
|
setTopicsContext((topicsContext: TopicsContext) => ({ |
|
...topicsContext, |
|
generation: "error", |
|
})) |
|
log(`Topic: ${initialTopic.id} -> generation error (${e.message}).`) |
|
}); |
|
}, |
|
importTopic: (json: string): void => { |
|
const error = (message: string): void => { |
|
throw new Error(message) |
|
} |
|
try { |
|
const object = JSON.parse(json); |
|
const id = generateUUID(); |
|
const topic: Topic = { |
|
id: id, |
|
title: typeof object.title == "string" ? object.title : error("title must be a string"), |
|
posts: object.posts instanceof Array ? object.posts.map((object: unknown): Post => ({ |
|
user: typeof object.user == "string" ? object.user : error("posts.user must be a string"), |
|
date: typeof object.date == "string" ? object.date : error("posts.date must be a string"), |
|
generationDate: typeof object.generationDate == "string" || object.generationDate === null ? object.generationDate : error("posts.generationDate must be null or string"), |
|
content: typeof object.content == "string" ? object.content : error("posts.content must be a string"), |
|
})) : error("posts must be a string"), |
|
} |
|
setTopicsContext({ |
|
...topicsContext, |
|
topics: [...topicsContext.topics, topic], |
|
import: "done", |
|
}); |
|
} catch (e) { |
|
console.error(e); |
|
setTopicsContext({ |
|
...topicsContext, |
|
import: "error", |
|
}); |
|
} |
|
} |
|
}, |
|
}) |
|
}) |
|
|
|
|