import request from 'superagent'
import { v1 as uuidV1 } from 'uuid'
import { io } from 'socket.io-client'
import { createHash , hmacHex } from './crypto.js'
import { isObject } from './util.js'
import { aoEnv } from './settings.js'
// The AO API server endpoint this ao-cli client will attempt to connect to
export const AO _DEFAULT _HOSTNAME = 'localhost:8003'
const HOSTNAME = aoEnv ( 'AO_CLI_TARGET_HOSTNAME' ) || AO _DEFAULT _HOSTNAME
const [ HOST , PORT ] = HOSTNAME . split ( ':' )
// The AO API server websocket endpoint this ao-cli client will attempt to connect to
const AO _SOCKET _URL =
process . env . NODE _ENV === 'development' ? 'http://' + AO _DEFAULT _HOSTNAME : '/'
export const socket = io ( AO _SOCKET _URL , {
autoConnect : false
} )
// Load the current session cookies from the AO .env file
let currentMemberId = aoEnv ( 'AO_CLI_SESSION_USERNAME' )
let currentSessionId = aoEnv ( 'AO_CLI_SESSION_ID' )
let currentSessionToken = aoEnv ( 'AO_CLI_SESSION_TOKEN' )
// Performs a post request to the specified endpoint, sending the given payload
export async function postRequest ( endpoint , payload ) {
if ( ! currentSessionToken ) {
console . log ( 'Session token not set, API not ready.' )
return new Promise ( ( ) => null )
}
try {
if ( payload ) {
return await request
. post ( HOSTNAME + endpoint )
. send ( payload )
. set ( 'authorization' , currentSessionToken )
. set ( 'session' , currentSessionId )
} else {
return await request . post ( HOSTNAME + endpoint )
. set ( 'authorization' , currentSessionToken )
. set ( 'session' , currentSessionId )
}
} catch ( err ) {
console . log ( 'request failed' , err )
return null
}
}
// Performs a post request to the /event endpoint, sending the given JSON object as the event
export async function postEvent ( event ) {
return await postRequest ( '/event' , event )
}
// Attempts login with the given username and password combo. If successful, returns the generated session and token (login cookies).
export async function createSession ( user , pass ) {
const session = uuidV1 ( )
let sessionKey = createHash ( session + createHash ( pass ) )
const token = hmacHex ( session , sessionKey )
const result = await request
. post ( HOSTNAME + '/session' )
. set ( 'authorization' , token )
. set ( 'session' , session )
. set ( 'name' , user )
. on ( 'error' , ( ) => false )
currentMemberId = result . body . memberId
currentSessionToken = token
currentSessionId = session // Not used in this api.js yet
return { session , token , memberId : currentMemberId }
}
export async function logout ( ) {
return await postRequest ( '/logout' )
}
// AO p2p over tor features
export async function nameAo ( newName ) {
return await postEvent ( {
type : 'ao-named' ,
alias : newName
} )
}
export async function connectToAo ( address , secret ) {
return await postEvent ( {
type : 'ao-outbound-connected' ,
address : address ,
secret : secret
} )
}
export async function deleteAoConnection ( address ) {
return await postEvent ( {
type : 'ao-disconnected' ,
address : address
} )
}
export async function relayEventToOtherAo ( address , event ) {
return await postEvent ( {
type : 'ao-relay' ,
address : address ,
ev : event
} )
}
export async function linkCardOnAo ( taskId , address ) {
return await postEvent ( {
type : 'ao-linked' ,
address : address ,
taskId : taskId
} )
}
// Avatar and presence features
export async function bark ( ) {
return await postEvent ( {
type : 'doge-barked' ,
memberId : currentMemberId
} )
}
export async function hopped ( taskId ) {
return await postEvent ( {
type : 'doge-hopped' ,
memberId : currentMemberId ,
taskId : taskId
} )
}
export async function mute ( ) {
return await updateMemberField ( 'muted' , true )
}
export async function unmute ( ) {
return await updateMemberField ( 'muted' , false )
}
// Memes feature
export async function fetchMeme ( memeHash , progressCallback ) {
return request
. get ( HOSTNAME + '/meme/' + memeHash )
. responseType ( 'blob' )
. set ( 'Authorization' , currentSessionToken )
. on ( 'progress' , function ( e ) {
progressCallback ( e . percent )
} )
. then ( res => {
console . log ( 'got meme! res is ' , res )
return res . body
} )
}
export async function downloadMeme ( memeHash ) {
return request
. get ( HOSTNAME + '/download/' + memeHash )
. set ( 'Authorization' , currentSessionToken )
. then ( res => {
// console.log('got meme! res is ', res)
return res
} )
}
export async function uploadMemes ( formData , progressCallback ) {
return postRequest ( '/upload' , formData )
. on ( 'progress' , function ( e ) {
console . log ( 'Percentage done: ' , e )
if ( e && e . hasOwnProperty ( 'percent' ) && e . percent >= 0 ) {
progressCallback ( e . percent )
}
} )
. on ( 'error' , err => {
console . log ( 'Upload failed with error:' , err )
return false
} )
. then ( res => {
console . log ( 'sent files. res is' , res )
return res
} )
}
export async function cacheMeme ( taskId ) {
return await postEvent ( {
type : 'meme-cached' ,
taskId
} )
}
// Cards feature
export async function getCard ( taskId , alsoGetRelevant = 'subcards' ) {
taskId = taskId . trim ( ) . toLowerCase ( )
let payload = { taskId : taskId }
const result = await postRequest ( '/fetchTaskByID' , payload ) // todo: change to flat text, not JSON
if ( ! result || ! result . body ) {
console . log ( 'Error fetching task.' )
return null
}
if ( alsoGetRelevant ) {
let relevantCards = await getAllRelevantCards ( result . body , alsoGetRelevant )
return [ result . body , ... relevantCards ]
}
return [ result . body ]
}
// Fetches all cards related to the given card object, i.e., cards that could be seen or navigated to immediately from that card
// scope = 'priority' returns only the first/top priority card within the specified card
// scope = 'priorities' returns only the priorities within the specified card
// scope = 'subcards' returns all subcards (priorities, pinned, subTasks, completed)
// Further scopes are not currently needed because the server also includes some related cards with each send
// If existingTasks: Map<string, Task> is provided, those cards will be skipped
// Returns the new cards that were fetched (not any existingTasks), plus cards the server chooses to also include
export async function getAllRelevantCards (
seedTask ,
scope = 'priorities' ,
existingTasks
) {
if ( existingTasks === undefined ) {
existingTasks = new Map ( )
}
let taskIdsToFetch
// Choose which taskIds we are going to request from the server
switch ( scope ) {
case 'priority' :
taskIdsToFetch = new Set ( [ seedTask . priorities . at ( - 1 ) ] )
break
case 'priorities' :
taskIdsToFetch = new Set ( seedTask . priorities )
break
case 'subcards' :
taskIdsToFetch = new Set (
seedTask . priorities . concat ( seedTask . subTasks , seedTask . completed )
)
if ( seedTask . pins && seedTask . pins . length >= 1 ) {
seedTask . pins . forEach ( pin => {
taskIdsToFetch . add ( pin . taskId )
} )
}
}
// Filter out the taskIds for tasks we already have
taskIdsToFetch = [ ... taskIdsToFetch ] . filter ( taskId => {
if ( ! taskId ) {
return false
}
const existingTask = existingTasks . get ( taskId )
return ! existingTask
} )
if ( taskIdsToFetch . length < 1 ) {
return [ ]
}
// Fetch the cards
try {
const result = await postRequest ( '/fetchTasks' , { taskIds : taskIdsToFetch } )
// Filter again (overlapping queries or intelligent server can cause duplicates to be returned)
const newTasksOnly = result . body . filter (
fetchedTask => ! existingTasks . get ( fetchedTask . taskId )
)
return newTasksOnly
} catch ( error ) {
console . log ( 'Error fetching relevant tasks:' , { taskIdsToFetch , error } )
return null
}
}
export async function colorCard ( taskId , color ) {
return await postEvent ( {
type : 'task-colored' ,
taskId : taskId ,
color : color ,
inId : null , // add this when we have context, mutation works on server
blame : currentMemberId
} )
}
export async function setCardProperty ( taskId , property , value ) {
return await postEvent ( {
type : 'task-property-set' ,
taskId : taskId ,
property : property ,
value : value ,
blame : currentMemberId
} )
}
// Card send feature
export async function passCard ( taskId , toMemberId ) {
return await postEvent ( {
type : 'task-passed' ,
taskId : taskId ,
toMemberId : toMemberId ,
fromMemberId : currentMemberId
} )
}
export async function remindMember ( memberId ) {
return await postEvent ( {
type : 'member-reminded' ,
toMemberId : memberId ,
fromMemberId : currentMemberId
} )
}
// Cards-in-cards feature
export async function playCard ( from = null , to ) {
return await postEvent ( {
type : 'task-played' ,
from : from ,
to : to ,
memberId : currentMemberId
} )
}
export async function discardCardFromCard ( taskId , inId ) {
return await postEvent ( {
type : 'task-de-sub-tasked' ,
taskId : taskId ,
subTaskId ,
blame : currentMemberId
} )
}
// Empties a card's priorities and subtasks
export async function emptyCard ( taskId ) {
return await postEvent ( {
type : 'task-emptied' ,
taskId : taskId ,
blame : currentMemberId
} )
}
export async function swapCard ( inId , taskId1 , taskId2 ) {
return await postEvent ( {
type : 'task-swapped' ,
taskId : inId ,
swapId1 : taskId1 ,
swapId2 : taskId2 ,
blame : currentMemberId
} )
}
export async function bumpCard ( taskId , inId , direction ) {
return await postEvent ( {
type : 'task-bumped' ,
taskId : inId ,
bumpId : taskId ,
direction : direction ,
blame : currentMemberId
} )
}
// Deck features
export async function grabCard ( taskId ) {
return await postEvent ( {
type : 'task-grabbed' ,
taskId : taskId ,
memberId : currentMemberId
} )
}
export async function grabPile ( taskId ) {
return await postEvent ( {
type : 'pile-grabbed' ,
taskId : taskId ,
memberId : currentMemberId
} )
}
export async function dropCard ( taskId ) {
return await postEvent ( {
type : 'task-dropped' ,
taskId : taskId ,
memberId : currentMemberId
} )
}
export async function removeCards ( taskIds ) {
return await postEvent ( {
type : 'tasks-removed' ,
taskIds : taskIds ,
memberId : currentMemberId
} )
}
export async function dropPile ( taskId ) {
return await postEvent ( {
type : 'pile-dropped' ,
taskId : taskId ,
memberId : currentMemberId
} )
}
// Priority feature
export async function prioritizeCard ( taskId , inId , position = 0 ) {
return await postEvent ( {
type : 'task-prioritized' ,
taskId ,
inId : inId ,
position : position ,
blame : currentMemberId
} )
}
export async function prioritizePile ( inId ) {
return await postEvent ( {
type : 'task-prioritized' ,
inId : inId
} )
}
export async function refocusCard ( taskId , inId ) {
return await postEvent ( {
type : 'task-refocused' ,
taskId : taskId ,
inId : inId ,
blame : currentMemberId
} )
}
export async function refocusPile ( inId ) {
return await postEvent ( {
type : 'pile-refocused' ,
inId : inId
} )
}
export async function allocatePriority ( inId , taskId , points = 1 ) {
return await postEvent ( {
type : 'task-allocated' ,
taskId : inId ,
allocatedId : taskId ,
amount : points ,
blame : currentMemberId
//inId: inId,
} )
}
// Guilds feature
export async function titleMissionCard ( taskId , newTitle ) {
return await postEvent ( {
type : 'task-guilded' ,
taskId : taskId ,
guild : newTitle ,
blame : currentMemberId
} )
}
// Checkmarks feature
export async function completeCard ( taskId ) {
return await postEvent ( {
type : 'task-claimed' ,
taskId : taskId ,
memberId : currentMemberId
} )
}
export async function uncheckCard ( taskId ) {
return await postEvent ( {
type : 'task-unclaimed' ,
taskId : taskId ,
memberId : currentMemberId
} )
}
export async function setClaimInterval ( taskId , newClaimInterval ) {
return await setCardProperty ( taskId , claimInterval , newClaimInterval )
}
// Hardware resources feature
export async function createResource (
resourceId ,
name ,
charged ,
secret ,
trackStock
) {
return await postEvent ( {
type : 'resource-created' ,
resourceId : resourceId ,
name : name ,
charged : charged ,
secret : secret ,
trackStock : trackStock ,
blame : currentMemberId
} )
}
export async function useResource ( resourceId , amount , charged , notes = '' ) {
return await postEvent ( {
type : 'resource-used' ,
resourceId : resourceId ,
memberId : currentMemberId ,
amount : amount ,
charged : charged ,
notes : notes
} )
}
export async function stockResource ( resourceId , amount , paid , notes = '' ) {
return await postEvent ( {
type : 'resource-stocked' ,
resourceId : resourceId ,
memberId : currentMemberId ,
amount : amount ,
paid : paid ,
notes : notes
} )
}
export async function purgeResource ( resourceId ) {
return await postEvent ( {
type : 'resource-purged' ,
resourceId : resourceId ,
blame : currentMemberId
} )
}
export async function bookResource ( taskId , startTime , endTime ) {
return await postEvent ( {
type : 'resource-booked' ,
resourceId : taskId ,
memberId : currentMemberId ,
startTs : startTime ,
endTs : endTime
} )
}
// Member account features
export async function updateMemberField ( field , newValue ) {
if ( field === 'secret' ) {
newValue = createHash ( newValue )
}
return await postEvent ( {
type : 'member-field-updated' ,
memberId : currentMemberId ,
field : field ,
newfield : newValue
} )
}
// Member admin features
export async function createMember ( name , fob = '' ) {
const secret = createHash ( name )
return await postEvent ( {
type : 'member-created' ,
name ,
secret ,
fob
} )
}
export async function activateMember ( memberId ) {
return await postEvent ( {
type : 'member-activated' ,
memberId : memberId
} )
}
export async function deactivateMember ( memberId ) {
return await postEvent ( {
type : 'member-deactivated' ,
memberId : memberId
} )
}
// senpai function
export async function resetPassword ( memberId ) {
return await postEvent ( {
type : 'member-secret-reset' ,
kohaiId : memberId ,
senpaiId : currentMemberId
} )
}
// senpai function
export async function promoteMember ( memberId ) {
return await postEvent ( {
type : 'member-promoted' ,
kohaiId : memberId ,
senpaiId : currentMemberId
} )
}
// senpai function
export async function banMember ( memberId ) {
return await postEvent ( {
type : 'member-banned' ,
kohaiId : memberId ,
senpaiId : currentMemberId
} )
}
// senpai function
export async function unbanMember ( memberId ) {
return await postEvent ( {
type : 'member-unbanned' ,
kohaiId : memberId ,
senpaiId : currentMemberId
} )
}
// senpai function
export async function purgeMember ( memberId ) {
return await postEvent ( {
type : 'member-purged' ,
memberId : memberId ,
blame : currentMemberId
} )
}
// Each member has a list of tickers. Each ticker is a string.
// Sets the ticker at position tickerListIndex to symbol coinSymbol.
export async function setTicker ( fromCoin , toCoin , tickerListIndex ) {
return await postEvent ( {
type : 'member-ticker-set' ,
memberId : currentMemberId ,
fromCoin : fromCoin ,
toCoin : toCoin ,
index : tickerListIndex
} )
}
// Timeclock features
export async function clockTime ( seconds , taskId , date ) {
return await postEvent ( {
type : 'task-time-clocked' ,
taskId : taskId ,
memberId : currentMemberId ,
seconds : seconds ,
date : date
} )
}
export async function startTimeClock ( taskId , inId ) {
return await postEvent ( {
type : 'task-started' ,
taskId : taskId ,
inId : inId ,
memberId : currentMemberId
} )
}
export async function stopTimeClock ( taskId ) {
return await postEvent ( {
type : 'task-stopped' ,
taskId : taskId ,
memberId : currentMemberId
} )
}
// Group membership features
export async function assignMembership ( taskId , memberId , level ) {
return await postEvent ( {
type : 'task-membership' ,
taskId : taskId ,
memberId : memberId ,
level : level ,
blame : currentMemberId
} )
}
export async function stashCard ( taskId , inId , level ) {
return await postEvent ( {
type : 'task-stashed' ,
taskId : taskId ,
inId : inId ,
level : level ,
blame : currentMemberId
} )
}
export async function unstashCard ( taskId , inId , level ) {
return await postEvent ( {
type : 'task-unstashed' ,
taskId : taskId ,
inId : inId ,
level : level ,
blame : currentMemberId
} )
}
// Unreads feature
export async function visitCard ( taskId , inChat = false , notify = false ) {
return await postEvent ( {
type : 'task-visited' ,
taskId : taskId ,
memberId : currentMemberId ,
area : inChat ? 1 : 0 ,
notify : notify
} )
}
/ *
export async function markSeen ( taskId ) {
const task = aoStore . hashMap . get ( taskId )
const act = {
type : 'task-seen' ,
taskId : taskId ,
memberId : currentMemberId ,
}
// console.log('card marked seen')
return await postEvent ( act )
}
* /
// Pinboard feature
export async function resizeGrid ( taskId , newHeight , newWidth , newSize ) {
return await postEvent ( {
type : 'grid-resized' ,
taskId : taskId ,
height : newHeight ,
width : newWidth ,
size : newSize || 9
} )
}
export async function createCardWithGrid ( name , height , width ) {
return await postEvent ( {
type : 'grid-created' ,
name : name ,
height : height ,
width : width ,
color : 'blue' ,
deck : [ currentMemberId ]
} )
}
export async function addGridToCard ( taskId , height , width , spread = 'pyramid' ) {
return await postEvent ( {
type : 'grid-added' ,
taskId : taskId ,
spread : spread ,
height : height ,
width : width
} )
}
export async function removeGridFromCard ( taskId ) {
return await postEvent ( {
type : 'grid-removed' ,
taskId : taskId
} )
}
// This function encodes whatever is passed by the search box as a URIComponent and passes it to a search endpoint, returning the response when supplied
export async function search ( querystring , take = 10 , skip = 0 ) {
const qs = encodeURIComponent ( querystring )
const params = ` ?take= ${ take } &skip= ${ skip } `
return await postRequest ( '/search/' + qs + params )
}
export async function requestBtcQr ( taskId ) {
return await postEvent ( {
type : 'address-updated' ,
taskId
} )
}
export async function requestLightningInvoice ( taskId , amount = 0 ) {
return await postEvent ( {
type : 'invoice-created' ,
taskId ,
amount : amount
} )
}
// Proposals features
export async function signCard ( taskId , opinion = 1 ) {
return await postEvent ( {
type : 'task-signed' ,
taskId : taskId ,
memberId : currentMemberId ,
opinion : opinion
} )
}
export async function setQuorum ( quorum ) {
return await postEvent ( {
type : 'quorum-set' ,
quorum : quorum
} )
}
/ * s t a r t S o c k e t L i s t e n e r s ( ) {
this . socket . connect ( )
this . socket . on ( 'connect' , ( ) => {
console . log ( 'connected' , { 'aoStore.state' : aoStore . state } )
runInAction ( ( ) => {
aoStore . state . socketState = 'attemptingAuthentication'
const loadedSession = window . localStorage . getItem ( 'session' )
if ( loadedSession ) {
aoStore . state . session = loadedSession
}
const loadedToken = window . localStorage . getItem ( 'token' )
if ( loadedToken ) {
currentSessionToken = loadedToken
}
} )
console . log (
'emit auth: session: ' +
window . localStorage . getItem ( 'session' ) +
', token: ' +
window . localStorage . getItem ( 'token' )
)
this . socket . emit ( 'authentication' , {
session : window . localStorage . getItem ( 'session' ) ,
token : window . localStorage . getItem ( 'token' ) ,
} )
} )
this . socket . on ( 'authenticated' , ( ) => {
console . log ( 'authenticated' )
this . fetchState ( ) . then ( ( ) => {
runInAction ( ( ) => {
aoStore . state . socketState = 'authenticationSuccess'
} )
} )
this . socket . on ( 'eventstream' , ev => {
console . log ( 'AO: client/api.ts: socketListener: event:' , ev )
aoStore . applyEvent ( ev )
} )
} )
this . socket . on ( 'disconnect' , reason => {
console . log ( 'disconnected' )
runInAction ( ( ) => {
aoStore . state . socketState = 'authenticationFailed'
} )
this . socket . connect ( )
} )
} * /
/ * r e a c t i o n (
( ) => {
//return aoStore.state.socketState
} ,
socketState => console . log ( 'AO: client/api.ts: socketState: ' + socketState )
)
console . log ( "NODE_ENV is" , process . env . NODE _ENV ) * /
//const api = new AoApi(socket)
//export default api
/ * a s y n c f e t c h S t a t e ( ) {
const session = window . localStorage . getItem ( 'session' )
const token = window . localStorage . getItem ( 'token' )
const user = window . localStorage . getItem ( 'user' )
if ( session && token && user ) {
return request
. post ( '/state' )
. set ( 'Authorization' , token )
. then ( res => {
aoStore . state . user = user
// console.log(
// 'AO: client/api.ts: fetchState: initial state: ',
// res.body
// )
let dataPackageToSendToClient = res . body
// Get the memberId
let memberId
dataPackageToSendToClient . stateToSend . sessions . forEach ( sessionItem => {
if ( session === sessionItem . session ) {
memberId = sessionItem . ownerId
}
} )
// See if we got our member card
let foundMemberCard
if ( ! memberId ) {
console . log ( "memberId missing when loading state" )
} else {
dataPackageToSendToClient . stateToSend . tasks . forEach ( task => {
if ( task . taskId === memberId ) {
foundMemberCard = task
}
} )
}
if ( foundMemberCard ) {
console . log ( "State includes member card:" , foundMemberCard )
} else {
console . log ( "State does not include member card" )
}
aoStore . initializeState ( dataPackageToSendToClient . stateToSend )
let metaData = dataPackageToSendToClient . metaData
aoStore . memberDeckSize = metaData . memberDeckSize
aoStore . bookmarksTaskId = metaData . bookmarksTaskId
return true
} )
. catch ( ( ) => false )
}
return Promise . resolve ( false )
} * /
/ *
export async createCard (
name ,
anonymous
) {
const act = {
type : 'task-created' ,
name : name ,
color : 'blue' ,
deck : anonymous
? [ ]
: aoStore . member && currentMemberId
? [ currentMemberId ]
: [ ] ,
inId : anonymous ? null : aoStore . memberCard . taskId || null ,
prioritized : false ,
}
// console.log('AO: client/api.ts: createCard: ', {
// act,
// 'aoStore.memberCard': aoStore.memberCard,
// })
return await postEvent ( act )
}
* /
/ *
export async createCardIfDoesNotExist (
name ,
color ,
anonymous
) {
return new Promise ( ( resolve , reject ) => {
aoStore . getTaskByName _async ( name , ( task ) => {
if ( isObject ( task ) ) {
console . log ( "task exists!" )
resolve ( task )
} else {
const act = {
type : 'task-created' ,
name : name ,
color : color || 'blue' ,
deck : [ currentMemberId ] ,
inId : null ,
prioritized : false ,
}
postEvent ( act ) . then ( ( res ) => {
aoStore . getTaskByName _async ( name , ( task ) => {
resolve ( task )
} )
} )
}
} )
} )
}
* /
/ *
export async createAndPlayCard ( name , color , anonymous , to ) {
return new Promise ( ( resolve , reject ) => {
this . createCardIfDoesNotExist ( name , color , anonymous ) . then ( success => {
aoStore . getTaskByName _async ( name , found => {
to . taskId = found . taskId
resolve ( this . playCard ( null , to ) )
} )
} )
} )
}
* /
/ * a s y n c f i n d O r C r e a t e C a r d I n C a r d (
name ,
inId ,
prioritizedpostEvent ( act ) = false ,
color = 'blue' ,
anonymous
) {
return new Promise ( ( resolve , reject ) => {
aoStore . getTaskByName _async ( name , found => {
console . log ( 'gotTaskByName name was ' , name , 'and found is ' , found )
let act
if ( found ) {
if ( prioritized ) {
resolve ( this . prioritizeCard ( found . taskId , inId ) )
return
} else {
act = {
type : 'task-sub-tasked' ,
taskId : inId ,
subTask : found . taskId ,
memberId : anonymous ? null : currentMemberId ,
}
}
} else {
act = {
type : 'task-created' ,
name : name ,
color : color ,
deck : anonymous ? [ ] : [ currentMemberId ] ,
inId : inId ,
prioritized : prioritized ,
}
}
resolve (
postEvent ( act ) . then ( res => return res )
)
} )
} )
} * /
/ * a s y n c f u n c t i o n p i n C a r d T o G r i d (
x ,
y ,
name ,
inId
) {
return new Promise ( ( resolve , reject ) => {
aoStore . getTaskByName _async ( name , ( task ) => {
console . log ( 'gotTaskByName name was ' , name , 'and found is ' , task )
// console.log("AO: client/api.ts: pinCardToGrid: ", {x, y, name, inId, task})
if ( isObject ( task ) ) {
const fromLocation
const toLocation : CardLocation = {
taskId . taskId ,
inId : inId ,
coords : { y , x }
}
playCard ( )
} else {
const act = {
type : 'task-created' ,
name : name ,
color : 'blue' ,
deck : [ currentMemberId ] ,
inId : inId ,
prioritized : false ,
}
postEvent ( act ) . then ( res => {
const taskId = JSON . parse ( res . text ) . event . taskId
const gridAct = {
type : 'grid-pin' ,
inId : inId ,
taskId : taskId ,
x : x ,
y : y ,
memberId : currentMemberId ,
}
resolve (
request
. post ( '/events' )
. set ( 'Authorization' , currentSessionToken )
. send ( gridAct )
)
} )
}
} )
} )
} * /
/ * a s y n c f u n c t i o n u n p i n C a r d F r o m G r i d (
x ,
y ,
inId
) {
return await postEvent ( {
type : 'grid-unpin' ,
x ,
y ,
inId ,
} )
} * /