// View and create cards with the .subtask of other cards, which is an array of taskIds import { headerStyle } from './styles.js' import { aoEnv } from '../ao-lib/settings.js' import { getCard, postEvent } from '../ao-lib/api.js' import { getNewHighestEchelonScore } from './priority.js' import { createCardInteractive } from './cards.js' import { promptMenu } from './welcome.js' import { tagCardInteractive, viewTagMenu } from './tags.js' // Displays the subtasks of the given taskId in a menu. Selecting a card shows a menu for that card. If taskId is null, member card is used. // The terms tasks and cards are used mostly interchangeably in the code. For the user, 'subcards' is preferred for clarity/generality, // but can be used to refer either to the .subTasks or all of the cards in another card (including subTasks, priorities, completed, and pinned) export async function subcardsMenu(taskId = null, previousIndex = null) { console.log(`\n${headerStyle('Cards in My Hand')}`) let subtaskChoices = [] const memberId = aoEnv('AO_CLI_SESSION_MEMBERID') if(!memberId) { console.log('Not logged in.') return false } if(!taskId) { // Get the subtasks of my member card taskId = memberId } const fetchedCards = await getCard(taskId, 'subcards') // will fetch both priorities and subtasks in one array if(!fetchedCards || fetchedCards.length < 1) { console.log('Failed to fetch the specified card, this is bad.') return false } const card = fetchedCards[0] // first card is the requested card itself // Separate fetched cards into correct ordered list of priorities and subtasks let priorityCards = card.priorities.map((priorityTaskId, i) => { const priorityCard = fetchedCards.find(p => p.taskId === priorityTaskId) if(!priorityCard) { return 'Missing card, repair your database' } return priorityCard }) priorityCards.reverse() const subtaskCards = card.subTasks.map((subtaskTaskId, i) => { const subtaskCard = fetchedCards.find(st => st.taskId === subtaskTaskId) if(!subtaskCard) { return 'Missing card, repair your database' } return subtaskCard }) console.log('There are', subtaskCards.length, 'subcards in this card') subtaskChoices = subtaskCards.map((subtaskCard, i) => { const shortenedName = subtaskCard.name.substring(0, 70) + (subtaskCard.name.length >= 70 ? '...' : '') return { title: shortenedName, value: { index: i, card: subtaskCard }, short: shortenedName } }) subtaskChoices.push( { title: 'Play card here', value: 'create_here', short: 'new card' }, { title: 'Back Up', value: false, short: 'back' } ) const cardName = taskId === memberId ? 'My Hand' : card.name.substring(0, 70).toTitleCase() const answer = await promptMenu(subtaskChoices, 'Cards in ' + cardName, undefined, previousIndex) switch(answer) { case false: return false case 'create_here': let previousCardCreatedText do { previousCardCreatedText = await createCardInteractive() console.log('done with round') } while(previousCardCreatedText != '\n') console.log('returning true') return answer.index case 'Missing card, repair your database': console.log('Database repair yet implemented, sorry.') return answer.index } if(answer === false) { return previousIndex } let chosenTask = answer.card const chosenTaskId = chosenTask.taskId let previousAnswer do { previousAnswer = await subtaskCardMenu(chosenTask, answer.index, taskId, priorityCards) // send priorities for echelon info in case they upboat 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) return answer.index } // Short action-oriented menu for cards in the subtasks list // Index is the position of the card in the list that it is in, used for fencepost case to display upboat contextually // inId is the taskId of the parent card that we are in contextually as we look at the given card in its list // allPriorities is an array of task objects for the other priorities in the .priorities for the card this card is in (adjacent to this card) async function subtaskCardMenu(card, index, inId, allPriorities) { if(!card) { console.log('subtaskCardMenu: 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) const guild = card.guild === true ? card.name.toTitleCase() : card.guild || false let subtaskChoices = [] const isInDeck = card.deck.includes(memberId) if(!isInDeck) { subtaskChoices.push({ title: 'Grab card (add to my deck)', value: 'grab', short: 'grab card' }) } subtaskChoices.push( { title: 'Discard from hand (downboat)', value: 'downboat', short: 'downboat' }, { title: 'Prioritize (upboat)', value: 'upboat', short: 'upboat' }, { title: isChecked ? 'Uncheck' : 'Check off', value: 'check', short: 'check!' }, { title: guild ? 'Tag: ' + guild : 'Tag', value: 'tag', short: 'tag' } ) if(guild) { subtaskChoices.push({ title: 'View tag', value: 'view_tag', short: 'view tag' }) } if(isInDeck) { subtaskChoices.push({ title: 'Remove from my deck', value: 'drop', short: 'drop card' }) } subtaskChoices.push( { title: 'Browse within', value: 'browse', short: 'browse' }, { title: 'Back Up', value: false, short: 'back' } ) const answer = await promptMenu(subtaskChoices, 'Card: ' + card.name) switch(answer) { case 'grab': await postEvent({ type: 'task-grabbed', taskId: taskId, memberId: memberId }) break case 'drop': await postEvent({ type: 'task-dropped', taskId: taskId, memberId: memberId }) break case 'check': if(isChecked) { await postEvent({ type: 'task-unclaimed', taskId: taskId, memberId: memberId }) } else { await postEvent({ type: 'task-claimed', taskId: taskId, memberId: memberId }) } break case 'tag': await tagCardInteractive(card) break case 'view_tag': while(await viewTagMenu(card.guild)) break case 'upboat': console.log('upboat') const { newPosition, newEchelonScore } = getNewHighestEchelonScore(card.echelon, allPriorities) //console.log('newPosition is', newPosition, 'and newEchelonScore is', newEchelonScore) await postEvent({ type: 'task-prioritized', taskId: taskId, inId: inId, position: newPosition, ...(newEchelonScore && { echelon: newEchelonScore }), }) return false case 'downboat': console.log(taskId, inId, 'discard') await postEvent({ type: 'task-de-sub-tasked', taskId: inId, subTask: taskId, }) return false case 'browse': let previousAnswer do { previousAnswer = await subcardsMenu(taskId, previousAnswer) // undefined taskId defaults to member card } while(previousAnswer !== false) {} break break default: return false } return true }