You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
212 lines
7.0 KiB
212 lines
7.0 KiB
2 years ago
|
// Cards module - everything related to cards should go here (database install is automatic for AO server so no feature module)
|
||
|
import inquirer from 'inquirer'
|
||
|
import { aoEnv } from './settings.js'
|
||
|
import { getCard, getCardByName, createCard, prioritizeCard, completeCard, uncheckCard, refocusCard } from './api.js'
|
||
|
import { headerStyle } from './styles.js'
|
||
|
|
||
|
// The card menu is complex and so has been split into this separate file
|
||
|
export async function cardMenu() {
|
||
|
console.log(`\n${headerStyle('My Deck')}`)
|
||
|
const cardChoices = [
|
||
|
{ name: 'Top priorities', value: 'priorities', short: 'priorities' }, // hand? (7) (add #s in parens)
|
||
|
{ name: 'Cards in hand', value: 'subcards', short: 'hand' }, // (current) deck? (60)
|
||
|
{ name: 'Browse full deck', value: 'browse', short: 'browse' }, // archive? (10,000)
|
||
|
'Back to AO Menu'
|
||
|
]
|
||
|
const answer = await inquirer.prompt({
|
||
|
name: 'card_menu',
|
||
|
type: 'list',
|
||
|
message: 'Please choose:',
|
||
|
choices: cardChoices,
|
||
|
pageSize: cardChoices.length,
|
||
|
})
|
||
|
switch(answer.card_menu) {
|
||
|
case 'priorities':
|
||
|
while(await prioritiesMenu()) {}
|
||
|
break
|
||
|
case 'subcards':
|
||
|
while(await subcardsMenu()) {}
|
||
|
break
|
||
|
case 'browse':
|
||
|
while(await browseMenu()) {}
|
||
|
break
|
||
|
default:
|
||
|
return false
|
||
|
}
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
// Displays the priorities of the given taskId in a menu. Selecting a card shows a menu for that card. If taskId is null, member card is used.
|
||
|
async function prioritiesMenu(taskId = null) {
|
||
|
console.log(`\n${headerStyle('My Priorities')}`)
|
||
|
let prioritiesChoices = []
|
||
|
|
||
|
const memberId = aoEnv('AO_CLI_SESSION_MEMBERID')
|
||
|
if(!memberId) {
|
||
|
console.log('Not logged in.')
|
||
|
return false
|
||
|
}
|
||
|
if(!taskId) {
|
||
|
// Get the priorities of my member card
|
||
|
taskId = memberId
|
||
|
}
|
||
|
const fetchedCards = await getCard(taskId, 'priorities')
|
||
|
if(!fetchedCards || fetchedCards.length < 1) {
|
||
|
console.log('Failed to fetch member card, this is bad.')
|
||
|
return false
|
||
|
}
|
||
|
const card = fetchedCards[0]
|
||
|
const priorityCards = fetchedCards.slice(1) // First card is member card itself
|
||
|
let priorities = card.priorities.slice()
|
||
|
priorities.reverse()
|
||
|
console.log('You have', priorityCards.length, 'priorities:')
|
||
|
prioritiesChoices = priorities.map((priorityTaskId, i) => {
|
||
|
const priorityCard = priorityCards.find(p => p.taskId === priorityTaskId)
|
||
|
if(!priorityCard) {
|
||
|
return 'Missing card, repair your database'
|
||
|
}
|
||
|
return {
|
||
|
name: priorityCard.name,
|
||
|
value: { index: i, card: priorityCard },
|
||
|
short: priorityCard.name.substring(0, 70) + priorityCard.name.length >= 70 ? '...' : ''
|
||
|
}
|
||
|
})
|
||
|
prioritiesChoices.push(
|
||
|
{ name: 'Create priority', value: 'create_here', short: 'new priority' },
|
||
|
{ name: 'Back to AO Menu', value: false, short: 'back' }
|
||
|
)
|
||
|
const answer = await inquirer.prompt({
|
||
|
name: 'priorities_menu',
|
||
|
type: 'rawlist',
|
||
|
message: 'Please choose:',
|
||
|
choices: prioritiesChoices,
|
||
|
loop: false
|
||
|
})
|
||
|
switch(answer.priorities_menu) {
|
||
|
case false:
|
||
|
return false
|
||
|
case 'create_here':
|
||
|
let previousCardCreatedText
|
||
|
do {
|
||
|
console.log('previousCardCreatedText is', previousCardCreatedText)
|
||
|
previousCardCreatedText = await createCardInteractive()
|
||
|
} while(previousCardCreatedText != '\n')
|
||
|
return true
|
||
|
case 'Missing card, repair your database':
|
||
|
console.log('Database repair yet implemented, sorry.')
|
||
|
return true
|
||
|
}
|
||
|
let chosenTask = answer.priorities_menu.card
|
||
|
const chosenTaskId = chosenTask.taskId
|
||
|
let previousAnswer
|
||
|
do {
|
||
|
previousAnswer = await priorityCardMenu(chosenTask, answer.priorities_menu.index)
|
||
|
if(previousAnswer) {
|
||
|
const fetchedCards = await getCard(chosenTaskId, false)
|
||
|
if(!fetchedCards || fetchedCards.length < 1) {
|
||
|
console.log('The card has disappeared. Maybe it was deleted, or cards held by no one are automatically cleaned up every five minutes.')
|
||
|
return false
|
||
|
}
|
||
|
chosenTask = fetchedCards[0]
|
||
|
}
|
||
|
} while(previousAnswer !== false)
|
||
|
console.log('Card menu not yet implemented.')
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
// Short action-oriented menu for cards in the priorities list
|
||
|
// Index is the position of the card in the list that it is in, used for fencepost case to display upboat contextually
|
||
|
async function priorityCardMenu(card, index) {
|
||
|
if(!card) {
|
||
|
console.log('priorityCardMenu: card is required.')
|
||
|
return false
|
||
|
}
|
||
|
const taskId = card.taskId
|
||
|
const memberId = aoEnv('AO_CLI_SESSION_MEMBERID')
|
||
|
if(!memberId) {
|
||
|
console.log('Not logged in.')
|
||
|
return false
|
||
|
}
|
||
|
const isChecked = card.claimed.includes(memberId)
|
||
|
console.log(`\n${headerStyle('Priority: ' + card.name)}`)
|
||
|
let priorityChoices = []
|
||
|
if(index != 0) {
|
||
|
priorityChoices.push({ name: 'Upboat', value: 'upboat', short: 'upboat' })
|
||
|
}
|
||
|
priorityChoices.push(
|
||
|
{ name: isChecked ? 'Uncheck' : 'Check off', value: 'check', short: 'check!' },
|
||
|
{ name: 'Downboat', value: 'downboat', short: 'downboat' },
|
||
|
//{ name: 'Browse within', value: 'browse', short: 'browse' }
|
||
|
{ name: 'Back to Priorities', value: false, short: 'back' }
|
||
|
)
|
||
|
const answer = await inquirer.prompt({
|
||
|
name: 'priority_card_menu',
|
||
|
type: 'list',
|
||
|
message: 'Please choose:',
|
||
|
choices: priorityChoices,
|
||
|
pageSize: priorityChoices.length,
|
||
|
})
|
||
|
switch(answer.priority_card_menu) {
|
||
|
case 'check':
|
||
|
if(isChecked) {
|
||
|
await uncheckCard(taskId)
|
||
|
} else {
|
||
|
await completeCard(taskId)
|
||
|
}
|
||
|
break
|
||
|
case 'upboat':
|
||
|
await prioritizeCard(taskId, memberId)
|
||
|
return false
|
||
|
case 'downboat':
|
||
|
await refocusCard(taskId, memberId)
|
||
|
return false
|
||
|
case 'browse':
|
||
|
break
|
||
|
default:
|
||
|
return false
|
||
|
}
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
async function subcardsMenu() {
|
||
|
console.log('Not yet implemented')
|
||
|
}
|
||
|
|
||
|
async function browseMenu() {
|
||
|
console.log('Not yet implemented')
|
||
|
}
|
||
|
|
||
|
// Ask the user to create a card, checks if it already exists, and then creates it if it doesn't
|
||
|
async function createCardInteractive(prioritized = true) {
|
||
|
const memberId = aoEnv('AO_CLI_SESSION_MEMBERID')
|
||
|
if(!memberId) {
|
||
|
console.log('Not logged in.')
|
||
|
return false
|
||
|
}
|
||
|
const answer = await inquirer.prompt({
|
||
|
name: 'new_card_text',
|
||
|
type: 'input',
|
||
|
message: 'New card or Enter to end:',
|
||
|
})
|
||
|
if(answer.new_card_text.trim().length <= 0) {
|
||
|
return false
|
||
|
}
|
||
|
// Check if the card alerady exists
|
||
|
const fetchedCards = await getCardByName(answer.new_card_text, false)
|
||
|
if(fetchedCards && fetchedCards.length >= 1) {
|
||
|
if(fetchedCards.length >= 2) {
|
||
|
console.log('More than one copy of this card was found. This should not happen.')
|
||
|
}
|
||
|
if(prioritized) {
|
||
|
console.log('Card already exists, prioritizing.')
|
||
|
const prioritizeResult = prioritizeCard(fetchedCards[0].taskId, memberId)
|
||
|
if(!prioritizeResult.ok) {
|
||
|
console.log('May have failed to prioritize card.')
|
||
|
}
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
console.log('card does not exist yet. creating...', answer.new_card_text)
|
||
|
const result = await createCard(answer.new_card_text, false, true)
|
||
|
return answer.new_card_text
|
||
|
}
|