👩‍💻 feat: save new time entry

This commit is contained in:
ysandler 2020-09-20 01:03:54 -05:00 committed by Joshua Shoemaker
parent 74c11dc53c
commit 71b66181d4
7 changed files with 285 additions and 57 deletions

View File

@ -0,0 +1,10 @@
interface TimeEntryInterface {
id?: number,
projectId: number,
taskId: number,
date: string,
notes: string,
isRunning?: boolean
}
export default TimeEntryInterface

View File

@ -37,4 +37,6 @@ class ProjectCollection {
})
return project
}
}
}
export default ProjectCollection

View File

@ -1,44 +1,84 @@
import * as vscode from "vscode";
import Harvest from "../../Entities/Harvest"
import UserInterface from "../../Entities/Interfaces/UserInterface";
import User from "../../Entities/User"
import getUser from "../getUser";
import TaskInterface from "../../Entities/Interfaces/TaskInterface";
import TimeEntryInterface from "../../Entities/Interfaces/TimeEntryInterface";
import Project from "../../Entities/Project";
import ProjectCollection from "../../Entities/ProjectCollection";
import saveNewTimeEntry from "../saveNewTimeEntry";
import SetupHarvest from "../SetupHarvest"
function PunchTime (context: vscode.ExtensionContext): vscode.Disposable {
return vscode.commands.registerCommand('harvest-vscode.punchTime', async () => {
const harvest = new Harvest()
let user = new User()
const accountId: string = context.globalState.get('accountId') || ''
const accessToken: string = context.globalState.get('accessToken') || ''
if (!accountId || !accessToken) {
vscode.window.showErrorMessage('Run "Harvest: Login" Command before trying to puch time')
let projectCollection = new ProjectCollection()
const isHarvestSetup = await SetupHarvest(context)
if (!isHarvestSetup) return
const projectNames = projectCollection.elements.map((p: Project) => {
return p.name
})
const selectedProjectName = await vscode.window.showQuickPick(projectNames, {
ignoreFocusOut: true,
placeHolder: 'Choost a Project'
})
if (!selectedProjectName) {
vscode.window.showWarningMessage('Must select a project to push time')
return
}
harvest.accountId = accountId
harvest.accessToken = accessToken
const selectedProject = projectCollection.findByName(selectedProjectName)
if (!user.id) {
let userProps: UserInterface
try {
userProps = await getUser()
} catch (err) {
console.log(err)
vscode.window.showErrorMessage('Could not retrieve user data from Harvest')
return
}
if (!userProps.id) {
vscode.window.showErrorMessage('Could not retrieve user data from Harvest')
return
}
user.destructor()
user = new User(userProps)
vscode.window.showInformationMessage('Successfully authenticated with Harvest')
const taskNames = selectedProject?.tasks.map((t: TaskInterface) => {
return t.name
})
if (!taskNames) {
vscode.window.showWarningMessage('No tasks defined for this project.')
return
}
console.log(user)
const selectedTaskName = await vscode.window.showQuickPick(taskNames, {
ignoreFocusOut: true,
placeHolder: 'Choost a Task'
})
if (!selectedTaskName) {
vscode.window.showWarningMessage('Must select a task to push time')
return
}
const selectedTask = selectedProject?.tasks.find((t: TaskInterface) => {
return t.name === selectedTaskName
})
// console.log(selectedProject?.tasks[0])
// console.log(selectedProject?.tasks[1])
// console.log(selectedProject?.tasks[2])
console.log(selectedTask)
const notes = await vscode.window.showInputBox({
ignoreFocusOut: true,
placeHolder: 'Notes'
})
if (!notes) {
vscode.window.showWarningMessage('Must add notes to puch time.')
return
}
const newTimeEntry: TimeEntryInterface = {
projectId: selectedProject!.id,
taskId: selectedTask!.id,
date: new Date().toISOString(),
notes: notes
}
console.log(newTimeEntry)
const saveNewTimeEntryResponse = await saveNewTimeEntry(newTimeEntry)
console.log(saveNewTimeEntryResponse)
})
}

View File

@ -0,0 +1,63 @@
import * as vscode from "vscode"
import Harvest from "../Entities/Harvest"
import ProjectInterface from "../Entities/Interfaces/ProjectInterface"
import UserInterface from "../Entities/Interfaces/UserInterface"
import Project from "../Entities/Project"
import ProjectCollection from "../Entities/ProjectCollection"
import User from "../Entities/User"
import getProjectsAssignments from "./getProjectsAssignments"
import getUser from "./getUser"
async function SetupHarvest (context: vscode.ExtensionContext): Promise<boolean> {
const harvest = new Harvest()
let projectCollection = new ProjectCollection()
let user = new User()
const accountId: string = context.globalState.get('accountId') || ''
const accessToken: string = context.globalState.get('accessToken') || ''
if (!accountId || !accessToken) {
vscode.window.showErrorMessage('Run "Harvest: Login" Command before trying to puch time')
return false
}
harvest.accountId = accountId
harvest.accessToken = accessToken
if (!user.id) {
vscode.window.showInformationMessage('Authenticating with Harvest')
let userProps: UserInterface
try {
userProps = await getUser()
} catch (err) {
console.log(err)
vscode.window.showErrorMessage('Could not retrieve user data from Harvest')
return false
}
if (!userProps.id) {
vscode.window.showErrorMessage('Could not retrieve user data from Harvest')
return false
}
user.destructor()
user = new User(userProps)
}
if (projectCollection.elements.length <= 0) {
vscode.window.showInformationMessage('Getting Projects from Harvest')
try {
let projectsData = await getProjectsAssignments()
const projects = projectsData.map((p: ProjectInterface) => {
return new Project(p)
})
projectCollection.addMany(projects)
} catch (err) {
console.log(err)
vscode.window.showErrorMessage('Could not retrieve uer projects')
return false
}
}
return true
}
export default SetupHarvest

View File

@ -1,36 +1,50 @@
import axios from 'axios'
import Harvest from '../Entities/Harvest'
import ErrorMessage from '../Constants/ErrorMessageInterface'
import ErrorMessages from '../Constants/ErrorMessages'
import ProjectInterface from '../Entities/Interfaces/ProjectInterface'
const getProjectsAssignments = async (): Promise<ProjectInterface[] | ErrorMessage> => {
const getProjectsAssignments = async (): Promise<ProjectInterface[]> => {
const harvest = new Harvest()
let projectsResponse: any
try {
projectsResponse = await axios.get(
'https://api.harvestapp.com/v2/users/me/project_assignments',
{ headers : harvest.headers }
)
} catch (err) {
console.log(err)
return ErrorMessages[1]
}
const projects = projectsResponse.data.project_assignments.map((p: any) => {
return {
id: p.project.id,
name: p.project.name,
tasks: p.task_assignments.map((t: any) => {
return {
id: t.task.id,
name: t.task.name
}
})
}
const projectResponses: any = await _getManyProjectPagesFromApi(harvest)
let projects: ProjectInterface[] = []
projectResponses.forEach((reponse: any) => {
const projectResponss: ProjectInterface[] = reponse.data.project_assignments.map((p: any) => {
return {
id: p.project.id,
name: p.project.name,
tasks: p.task_assignments.map((t: any) => {
return {
id: t.task.id,
name: t.task.name
}
})
}
})
projects = [...projects, ...projectResponss]
})
return projects
}
let projectPageRresonses: any = []
const _getManyProjectPagesFromApi = async (harvest: Harvest, nextPageUrl?: string): Promise<any> => {
let projectsResponse: any
try {
projectsResponse = await axios.get(
nextPageUrl || 'https://api.harvestapp.com/v2/users/me/project_assignments',
{ headers : harvest.headers }
)
projectPageRresonses.push(projectsResponse)
if (projectsResponse.data.links.next) await _getManyProjectPagesFromApi(harvest, projectsResponse.data.links.next)
} catch (err) {
console.log(err)
}
return projectPageRresonses
}
export default getProjectsAssignments

View File

@ -0,0 +1,38 @@
import axios from 'axios'
import Harvest from '../Entities/Harvest'
import TimeEntryInterface from '../Entities/Interfaces/TimeEntryInterface'
const saveNewTimeEntry = async (timeEntry: TimeEntryInterface): Promise<TimeEntryInterface> => {
const harvest = new Harvest()
const body = {
project_id: timeEntry.projectId,
task_id: timeEntry.taskId,
spent_date: timeEntry.date,
notes: timeEntry.notes
}
let timeEntryResponse: any
try {
timeEntryResponse = await axios.post(
'https://api.harvestapp.com/v2/time_entries',
body,
{ headers: harvest.headers }
)
} catch (err) {
console.log(err)
}
const createdTimeEntry: TimeEntryInterface = {
id: timeEntryResponse.data.id,
projectId: timeEntryResponse.data.project.id,
date: timeEntryResponse.data.spent_date,
taskId: timeEntryResponse.data.task.id,
notes: timeEntryResponse.data.notes,
isRunning: timeEntryResponse.data.is_running
}
return createdTimeEntry
}
export default saveNewTimeEntry

View File

@ -2,11 +2,12 @@ import ErrorMessage from "../../Constants/ErrorMessageInterface"
import Harvest from "../../Entities/Harvest"
import ProjectInterface from "../../Entities/Interfaces/ProjectInterface"
import Project from "../../Entities/Project"
import ProjectCollection from "../../Entities/ProjectCollection"
import getProjectsAssignments from '../../UseCases/getProjectsAssignments'
import env from '../env'
import UnitTest from "../UnitTestInterface"
const projectCreateInstance = async (): Promise<boolean> => {
const projectCreateInstance = (): boolean => {
const input: ProjectInterface = {
id: 10203,
name: 'Test Project',
@ -53,9 +54,69 @@ const getProjectsAssignmentsFromApi = async (): Promise<boolean> => {
else return false
}
const projectCollectionAddOne = (): boolean => {
new ProjectCollection().destructor()
const input: ProjectInterface = {
id: 10203,
name: 'Test Project',
tasks: [{
id: 123,
name: 'Test Task'
}]
}
const expectedOutput: ProjectInterface = {
id: 10203,
name: 'Test Project',
tasks: [{
id: 123,
name: 'Test Task'
}]
}
const project = new Project(input)
const collection = new ProjectCollection()
collection.addOne(project)
if (JSON.stringify(collection.elements[0].props) === JSON.stringify(expectedOutput)) return true
else return false
}
const projectCollectionAddMany = (): boolean => {
new ProjectCollection().destructor()
const input: ProjectInterface = {
id: 10203,
name: 'Test Project',
tasks: [{
id: 123,
name: 'Test Task'
}]
}
const expectedOutput: ProjectInterface = {
id: 10203,
name: 'Test Project',
tasks: [{
id: 123,
name: 'Test Task'
}]
}
const project = new Project(input)
const collection = new ProjectCollection()
collection.addMany([project])
if (JSON.stringify(collection.elements[0].props) === JSON.stringify(expectedOutput)) return true
else return false
}
const unitTests: UnitTest[] = [
{ name: 'Entity | Project Create Instance', test: projectCreateInstance },
{ name: 'Use Case | Get Projects From Api', test: getProjectsAssignmentsFromApi },
{ name: 'Collection | Add One To Project Collection', test: projectCollectionAddOne },
{ name: 'Collection | Add Many To Project Collection', test: projectCollectionAddMany },
]
export default unitTests