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

Add /icebreakers path to integrate with Icebreakers #123

Merged
merged 9 commits into from
Nov 17, 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
31 changes: 23 additions & 8 deletions src/components/DiscussionDisplay.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@
export let discussionId: string
export let title: string = ""
export let currentUser: User | undefined
const emptyTopicMessages = [
"Looks like this topic is waiting for its first thoughts. Be the pioneer and start the conversation!",
"This space is all yours! Kick off the discussion with your insights.",
"No comments yet. Share your perspective and spark the dialogue!",
"It's quiet here... Why not break the ice with your viewpoint?",
"A fresh topic awaits your input. Lead the way with your comment!",
]

let repliesFlatArray: (Comment & { isNew?: true })[] = []
let discussion: Discussion = {
Expand Down Expand Up @@ -49,9 +56,9 @@

const updateDiscussionDisplay = (
topic: Discussion,
topicReplies: Comment[]
topicReplies: Comment[] | undefined
) => {
repliesFlatArray = topicReplies
repliesFlatArray = topicReplies ?? []
discussion = threadComments(
topic,
topicReplies,
Expand All @@ -76,12 +83,13 @@
const { status, statusText, ok, body } = error as ServerResponse
if (ok) console.warn("Error handler caught an OK response", error)

if (
status === 404 &&
statusText === "Not Found" &&
body.startsWith("Topic")
) {
send("CREATE")
const isUnknownTopic =
status === 404 && statusText === "Not Found" && body.startsWith("Topic")

if (isUnknownTopic) {
setTimeout(() => {
send("CREATE")
}, 1)
return
}

Expand Down Expand Up @@ -183,6 +191,13 @@
</script>

<section class="simple-comment-discussion">
{#if !discussion?.replies}
<p class="instructions">
{emptyTopicMessages[
Math.floor(Math.random() * emptyTopicMessages.length)
]}
</p>
{/if}
{#if showReply === discussionId}
<CommentInput
commentId={discussionId}
Expand Down
3 changes: 2 additions & 1 deletion src/frontend-utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ type MinComment = {
*/
export const threadComments = <T extends MinComment, U extends MinComment>(
comment: T,
allComments: U[],
allComments: U[] | undefined,
sort: (a: U, b: U) => number = (a, b) => (b.id < a.id ? 0 : 1)
): T => {
if (!allComments) return { ...comment, replies: [] }
// Make this robust but warn
allComments = allComments.filter(reply => {
if (reply && reply.id) return true
Expand Down
2 changes: 1 addition & 1 deletion src/lib/discussion.xstate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const discussionMachine = createMachine<
DiscussionTypestate
>(
{
/** @xstate-layout N4IgpgJg5mDOIC5QQJawMYFdaxQewDsBaAMwBs8B3AOhQjLAGIBtABgF1FQAHPXAF3wEuIAB6IiAFgCcADmrSA7AFZFrSZNbTWi6coA0IAJ6IAjK1PVTANknKZagEzKlpgMwBfD4dQZsuQlIKGgoAQ1QCKEYAZQBVAGF4gFFo6LZOJBBeASERcQQiN1N5a0dbFxtpW2s3QxMER0US61ZZc2trPWLZRS8fNCwcISCqajCIqKSAJSmAeSn0kWyUQUI8iTdG6kVHWWULN1kepVrjREli6kk3SV1lTpt3U2U+kF9BgOJyUfQAJzBQoJIjEEslUotMstVsJMvlpJpqI5WG5WEjlLJHG4OpI6mZJI4FNIiXoUS5JEdrK93v5ht8aH8AUDJjN5hCeHwVrlYYh4axEcjUax0ZjsbiGrJpNR7o4ZG45Bcdo4qQMaYE6dQGYDICwOEsOdD1gVHGUpbdNJ09tcyWLTETqBLbmpZJ19sbZMq-EM1cExnhwtr4lMkgBBAAqSTZWX1XNA+Q0fJ02hRdnschlYqKBJ66k2jmKlVMHo+tJ9YF+vzwv0YQdDUwAmpGoTGxGZTIpEYpnnJpOZzLJWmL4dRrDY9hjTM9bPii6qvqXy5XGIGQ+HG9G1tyEOYdMOepo3PYdodTvVMZLWKUZLINLID4peq8CHgIHARNSvXOqHqchvYxJ7m41BuFieiKCOMhaDiZwFKUUoWLaeyND2SKUt4bwqh+Iw0HQDDfpyv4tgUyjPEBIFYmByJtKYYoyoSRysOoxqtA4M6Yeq4woJEeEGpuRDEcopEumBpgQfCNrSIBqLoioEEKqh-Sep8WEav8gKcVA3HNvkbRZtc1iqNojg9sBGYWAo1h7hKyL8SorFKeqmr8JAmkEfkE4XIiV63kUF6KIcNotMOSg9DKrTKAe8J2SWozjM5kLrjCf4FBo2wouo5pCsUEkGNBKKWFUllJjZUXeqMZYVr8LmJYRImAX2HQ6BZejSGKdgEneNSPK0VmeF4HhAA */
/** @xstate-layout N4IgpgJg5mDOIC5QQJawMYFdaxQewDsBaAMwBs8B3AOhQjLAGIBtABgF1FQAHPXAF3wEuIAB6IALAE4AHNQkB2AIwTWKpawUBWCToA0IAJ6IATKwDM1TUq0yAbOYkmtCu7IC+7g6gzZchUgoaCgBDVAIoRgBlAFUAYTiAUSiotk4kEF4BIRFxBGk5RRU1CQ1tXQkDYwQTaWoZVxMZEyVzOzclGXNPbzQsHCFAqmpQ8MjEgCUJgHkJtJEslEFCXMQFR3qW83N7CS67bSrEGwVqFy0Tc0uGuxUpOx6QH37-YnJh9AAnMBDBCOj4kkUvMMotlsIMnkTJdqCYpAopI4FHDdBolEcEOZ1vUpKw8dCruZWDIpI9nn5Bu8aF8fn9xlNZiCeHwljlIZItEpYV0SeYVBIsQiMbpTiTrIpbHZat0vE8+hSAlTqDTfpAWBwFizwat8rJ5MpVOpNDp9EZEOZOdQ7HjlBc7IoZKwpBIyfKBoqgiM8GE1QAZaYAQQAIkzMlq2aA8gV9cUjeVTdU4VIrTJUyoTMo1LdXb53W9PWBPp88J9GBNEgAVCYATVDYIjYkQMi0WmoUiUiKKOxMDkqZsxrBMbZaEntWjxTk0OZelILRZLjDi5YDFcSdfDK3ZCFxooUqjxWjsDQRWgx22o63tLWbUlvzqUnllBDwEDgInJeaGlE12U3kcQRB6koCItPcUrKPadgYkQWiWJK458k0Ap4lIWjTgq+bDHQDA-qyf6NpiyjyFIBLrGBNgmBiZhcsi7bIessGqA8sofq8X5emEKARLh2pble8hKAcZgZvaFpSFR8JnGojilDe9wPixbpsUqKp0jxDZ5DBrDUMBJEdu0GaCaOwpStQOx7g47Ydm07ToZ+KnfKqEDqfheRYnYxHXrYCJgQm5rjrCthNESFpqLeMq9LmymeqMkAuRC-6EVy0ikeY5GwRJNFHgc0gSHlzoyHZ0XDIWxafPFOrwh5uIkmYDQ6PlZ54rC2yocFpSsIej7uEAA */
id: "discussion-flow",
initial: "idle",
context: {},
Expand Down
26 changes: 26 additions & 0 deletions src/scss/simple-comment-style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -563,3 +563,29 @@ $highlight-text-color: color.scale(
background-color: inherit;
}
}

.icebreakers {
header {
max-width: 62rem;
align-items: flex-start;
margin: 3rem auto;

.headlines {
margin-left: 3rem;
h1,
h2 {
margin: 0;
padding: 0;
}

h2.icebreakers-logotype {
font-size: 2.2rem;
margin-bottom: 2rem;
}
}

p.instructions {
margin-bottom: 2rem;
}
}
}
78 changes: 78 additions & 0 deletions src/simple-comment-icebreakers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
declare global {
interface Window {
getQuestion: (slug: string) => Promise<string>
}
}
const storageKey = "icebreakerQuestions"
const timeStampKey = "icebreakerQuestionsTimeStamp"

const toSlug = (str: string): string =>
str
.toLowerCase()
.replace(/ /g, "-")
.replace(/[^\w-]+/g, "")
.replace(/_/g, "")
.replace(/-{2,}/g, "-")
.replace(/-$/, "")
.replace(/^-/, "")

const isSlugMatch = (slug: string, question: string) =>
slug === toSlug(question)

const reverseSlug = (slug: string, questions: string[]) =>
questions.find(question => isSlugMatch(slug, question))

const fetchAndStoreQuestions = () =>
new Promise<string[]>((resolve, reject) => {
const currentTimestamp =
document?.getElementById("questions-time-stamp")?.innerText || "0"
const storedTimestamp = localStorage.getItem(timeStampKey)

const isStoredQuestionsValid =
storedTimestamp && parseInt(storedTimestamp) >= parseInt(currentTimestamp)

const storedQuestions = localStorage.getItem(storageKey)
if (isStoredQuestionsValid && storedQuestions) {
resolve(JSON.parse(storedQuestions))
return
}

fetchQuestions(currentTimestamp, resolve, reject)
})

const fetchQuestions = async (currentTimestamp, resolve, reject) => {
try {
const questionFile = await fetch(
"https://raw.githubusercontent.com/rendall/icebreakers/master/QUESTIONS.md"
)
const questionsText = await questionFile.text()
const questionLines = questionsText.split("\n")
const questions = questionLines
.filter(line => /^ {2}\* [A-Z]/.test(line))
.map(line => line.slice(4))

localStorage.setItem(storageKey, JSON.stringify(questions))
localStorage.setItem(timeStampKey, currentTimestamp)
resolve(questions)
} catch (error) {
reject(error)
}
}

const getQuestion = (slug: string) =>
new Promise<string>((resolve, reject) => {
fetchAndStoreQuestions()
.then(questions => {
const question = reverseSlug(slug, questions)
if (question) {
resolve(question)
} else {
reject("No question found")
}
})
.catch(reject)
})

window.getQuestion = getQuestion

export default getQuestion
21 changes: 17 additions & 4 deletions src/simple-comment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,23 @@ import SimpleComment from "./components/SimpleComment.svelte"

declare global {
interface Window {
setSimpleCommentOptions: (setupOptions: { [key: string]: unknown }) => void
loadSimpleComment: (options: Options) => void
setSimpleCommentDiscussion: (discussionId: string) => void
setSimpleCommentOptions: (setupOptions: { [key: string]: unknown }) => void
}
}

let simpleComment

let options = {
cancel: false,
discussionId: getDefaultDiscussionId(),
title: document.title,
target: document.getElementById("simple-comment") ?? document.body,
title: document.title,
}

type Options = typeof options

/**
* Sets the options for the SimpleComment component.
* This function merges the provided options with the default options.
Expand Down Expand Up @@ -51,16 +55,25 @@ window.setSimpleCommentOptions = setupOptions =>
window.setSimpleCommentDiscussion = (discussionId: string) =>
window.setSimpleCommentOptions({ discussionId })

// Wait for DOMContentLoaded event before initializing SimpleComment
document.addEventListener("DOMContentLoaded", () => {
const loadSimpleComment = (setupOptions: Options) => {
options = { ...options, ...setupOptions }
simpleComment = new SimpleComment({
target: options.target,
props: { discussionId: options.discussionId, title: options.title },
})
}

window.loadSimpleComment = loadSimpleComment

// Wait for DOMContentLoaded event before initializing SimpleComment
document.addEventListener("DOMContentLoaded", () => {
if (options.cancel) return
else loadSimpleComment(options)
})

export default {
simpleComment,
setSimpleCommentOptions: window.setSimpleCommentOptions,
setSimpleCommentDiscussion: window.setSimpleCommentDiscussion,
loadSimpleComment: window.loadSimpleComment,
}
2 changes: 1 addition & 1 deletion src/static/_redirects
Original file line number Diff line number Diff line change
@@ -1 +1 @@
/topic/* /topic/index.html 200
/icebreakers/* /icebreakers/index.html 200
Loading