Skip to content

Commit

Permalink
+++
Browse files Browse the repository at this point in the history
  • Loading branch information
Offirmo committed Sep 29, 2024
1 parent aae4a5d commit 08ae641
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 109 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ first-mover advantage -- second mover advantage / "fast followers" / "free rider
first-mover advantage https://en.wikipedia.org/wiki/First-mover_advantage
funnel
Go-To-Market (GTM) = plan of an organization, utilizing their outside resources (e.g., sales force and distributors), to deliver their unique value proposition to customers and to achieve a competitive advantage https://en.wikipedia.org/wiki/Go-to-market_strategy
growth +++ https://growth.design/
growth -- concepts https://growth.design/psychology
growth -- labor perception / perceived labor https://growth.design/case-studies/labor-perception-bias
illegal practices -- monopoly
illegal practices -- payola https://en.wikipedia.org/wiki/Payola
illegal practices -- predatory pricing
Expand Down
2 changes: 2 additions & 0 deletions stack--current/5-incubator/active/view--chat/src/consts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

export const LIB = '@offirmo-private/view--chat'
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { PProgress as PromiseWithProgress } from 'p-progress'
import is_promise from 'is-promise'
import { type Immutable } from '@offirmo-private/ts-types'

import { LIB } from './consts.js'
import { type Step } from './types.js'
import { create_dummy_progress_promise } from './utils.js'

/////////////////////////////////////////////////

const LIB = '@offirmo-private/view--chat'

function is_step_input(step) {
function is_step_input(step: Immutable<Step>): boolean {
return step && step.type.startsWith('ask_')
}

Expand All @@ -19,89 +22,6 @@ function create({
}) {
if (DEBUG) console.log('↘ create()')

function create_dummy_progress_promise({DURATION_MS = 2000, PERIOD_MS = 100} = {}) {
return new PromiseWithProgress((resolve, reject, progress) => {
let count = 0
const auto_pulse = setInterval(() => {
count++
const completion_rate = 1. * (count * PERIOD_MS) / DURATION_MS
progress(completion_rate)

if (completion_rate >= 1) {
clearInterval(auto_pulse)
resolve()
}
}, PERIOD_MS)
})
}

function normalize_step(step) {
try {
if (step.type === 'ask_for_confirmation' && step !== STEP_CONFIRM)
step = Object.assign(
{},
STEP_CONFIRM,
step,
)

if (!step.msg_main)
throw new Error(`${LIB}: Step is missing main message!`)

if (!step.type) {
if (!step.choices)
throw new Error(`${LIB}: Step type is unknown and not inferrable!`)

step.type = 'ask_for_choice'
}

step = Object.assign(
{
validator: null,
choices: [],
},
step,
)

step.choices = step.choices.map(normalize_choice)

if (step.choices.length) {
const known_values = new Set()
step.choices.forEach((choice, index) => {
if (known_values.has(choice.value)) {
const err = new Error(`${LIB}: colliding choices with the same value!`)
err.details = {
choice,
value: choice.value,
index,
}
throw err
}
known_values.add(choice.value)
})
}


return step
}
catch (e) {
console.error(to_prettified_str(step))
throw e
}
}

function normalize_choice(choice) {
// TODO auto-id
try {
if (!choice.hasOwnProperty('value') || typeof choice.value === 'undefined')
throw new Error('Choice has no value!')
choice.msg_cta = choice.msg_cta || String(choice.value)
return choice
}
catch (e) {
console.error(to_prettified_str(choice))
throw e
}
}

async function ask_user(step) {
if (DEBUG) console.log('↘ ask_user(\n', to_prettified_str(step, {outline: true}), '\n)')
Expand Down
141 changes: 141 additions & 0 deletions stack--current/5-incubator/active/view--chat/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import { PProgress as PromiseWithProgress } from 'p-progress'

import { LIB } from './consts'

/////////////////////////////////////////////////


interface BaseStep {

}

interface SimpleMessageStep extends BaseStep {
type: 'simple_message'

msg: string
}

interface PerceivedLaborStep extends BaseStep {
type: 'perceived_labor'

msg_before?: string
duration_ms?: number
msg_after?: string
}

interface AskForConfirmationStep extends BaseStep {
type: 'ask_for_confirmation'

prompt?: string
msg_after?: (confirmation: boolean) => string

}

interface TaskProgressStep<T = any> extends BaseStep {
type: 'progress'

msg_before?: string
task_promise: Promise<T> | PromiseWithProgress<T>
msg_after?: (success: boolean, result: T | Error) => string
}

type Step =
| SimpleMessageStep
| PerceivedLaborStep
| AskForConfirmationStep
| TaskProgressStep



/*
type:
| 'ask_for_choice'
msg_main: string
msg_details?: string
choices?: {
value: string
label: string
}[]
validator?: (value: string) => boolean
}
*/


/////////////////////////////////////////////////

function normalize_step(step: Step) {
try {
if (step.type === 'ask_for_confirmation' && step !== STEP_CONFIRM)
step = Object.assign(
{},
STEP_CONFIRM,
step,
)

if (!step.msg_main)
throw new Error(`${LIB}: Step is missing main message!`)

if (!step.type) {
if (!step.choices)
throw new Error(`${LIB}: Step type is unknown and not inferrable!`)

step.type = 'ask_for_choice'
}

step = Object.assign(
{
validator: null,
choices: [],
},
step,
)

step.choices = step.choices.map(normalize_choice)

if (step.choices.length) {
const known_values = new Set()
step.choices.forEach((choice, index) => {
if (known_values.has(choice.value)) {
const err = new Error(`${LIB}: colliding choices with the same value!`)
err.details = {
choice,
value: choice.value,
index,
}
throw err
}
known_values.add(choice.value)
})
}


return step
}
catch (e) {
console.error(to_prettified_str(step))
throw e
}
}

function normalize_choice(choice) {
// TODO auto-id
try {
if (!choice.hasOwnProperty('value') || typeof choice.value === 'undefined')
throw new Error('Choice has no value!')
choice.msg_cta = choice.msg_cta || String(choice.value)
return choice
}
catch (e) {
console.error(to_prettified_str(choice))
throw e
}
}

/////////////////////////////////////////////////

export {
Step,
}
23 changes: 0 additions & 23 deletions stack--current/5-incubator/active/view--chat/src/utils.js

This file was deleted.

29 changes: 29 additions & 0 deletions stack--current/5-incubator/active/view--chat/src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { PProgress as PromiseWithProgress } from 'p-progress'
import assert from 'tiny-invariant'

/////////////////////////////////////////////////

function create_dummy_progress_promise({DURATION_MS = 2000, PERIOD_MS = 100} = {}): PromiseWithProgress<void> {
assert(PERIOD_MS < DURATION_MS, 'PERIOD_MS should be < DURATION_MS!')

return new PromiseWithProgress<void>((resolve, reject, progress) => {
let count = 0
let pulse = setInterval(() => {
count++
const completion_rate = 1. * (count * PERIOD_MS) / DURATION_MS
progress(completion_rate)

if (completion_rate >= 1) {
clearInterval(pulse)
pulse = null
resolve()
}
}, PERIOD_MS)
})
}

/////////////////////////////////////////////////

export {
create_dummy_progress_promise
}

0 comments on commit 08ae641

Please sign in to comment.