Article original : Free Course: Build an expense organizer with ES6 and Dropbox

Par Per Harald Borgen

Dans ma précédente startup, nous utilisions fortement l'API Dropbox dans notre processus de production. Nos produits étaient des applications de livres pour enfants sur iPad, et chaque livre était simplement une collection de dossiers Dropbox contenant toutes les images, la musique et les voix off pour le livre. Cela avait deux grands avantages : cela fournissait à tout le monde une interface qu'ils savaient déjà utiliser, et c'était moins cher que de construire une interface personnalisée.

Ainsi, lorsque Dropbox a demandé à Scrimba si nous serions intéressés à créer un cours sponsorisé sur leur API, il n'y avait aucun doute dans nos esprits, car nous savions à quel point leur API peut être utile.

Deuxièmement, ce sponsoring nous permet également de créer encore plus de cours pour notre communauté tout au long de 2019. Nous sommes donc très reconnaissants à Dropbox de s'intéresser à soutenir Scrimba.

Maintenant, jetons un coup d'œil au cours lui-même.

Introduction

L'instructeur de ce cours est Christian Jensen, un développeur front-end basé dans l'Utah. Certains d'entre vous le connaissent peut-être grâce aux tutoriels React Hooks qu'il a créés sur Scrimba l'année dernière, et que beaucoup de gens ont appréciés.

Image

Christian commence le cours en vous donnant un aperçu de ce que vous devriez savoir avant de commencer, et de ce que vous pouvez vous attendre à apprendre tout au long du cours.

Image

En tant que prérequis pour le cours, il serait bon de connaître, mais ce n'est pas nécessaire, quelques bases de HTML et de JavaScript. Si vous n'êtes pas vraiment familier avec JS, vous pouvez toujours suivre ce cours, car l'API se traduit très bien dans d'autres langues.

L'objectif final du cours est de vous rendre capable de construire une application sur la base de dossiers Dropbox, illustrée par l'application d'organisateur de dépenses que Christian construit tout au long des leçons.

Image

C'est un exemple parfait de quelque chose qui est une source de beaucoup de tracas pour de nombreuses entreprises et freelances, à savoir le suivi des reçus !

Installation

Avant de plonger dans le code, Christian nous donne un bref aperçu optionnel de l'installation pour ceux qui souhaitent exécuter l'application de ce tutoriel sur leur propre machine.

La première chose à faire est de se rendre sur Dropbox. Sur le site web de Dropbox, allez dans Mes applications et choisissez API Dropbox :

Image

Ensuite, nous choisissons le type d'accès Dossier d'application, juste pour voir comment cela fonctionne, et enfin, nous allons nommer notre application.

Après avoir cliqué sur le bouton Créer une application et après que notre application soit générée, nous voyons l'écran des paramètres.

Dans les paramètres, nous avons vraiment besoin uniquement de la section OAuth 2 et sous Jeton d'accès généré, cliquez sur le bouton Générer pour obtenir un jeton d'accès que nous utiliserons dans la prochaine partie de notre tutoriel.

C'est tout !

Importer le SDK

Dans ce cast, Christian nous montre comment importer le SDK et commencer à l'utiliser.

Une rapide note : même si dans ce cours le SDK JavaScript pour l'API Dropbox est utilisé, le SDK lui-même est essentiellement le même dans tous les langages de programmation.

Commençons par importer le SDK JavaScript.

// notez que l'import est nommé  
import { Dropbox } from 'dropbox';

La classe est instanciée avec un objet de configuration, qui nécessite accessToken et une bibliothèque de récupération. Nous allons utiliser fetch dans le cours et vous pouvez obtenir votre accessToken, si vous le souhaitez, dans votre compte développeur Dropbox.

import { Dropbox } from 'dropbox';

const dbx = new Dropbox({  
  accessToken: 'aeOL1E1HS0AAAAAAAAAALX6z1ogWy75HGE_HBN-NNpJNfhnEa1kjF1vsJ_t7Wf8k', 
  fetch  
})

Note : le accessToken ci-dessus a été révoqué, donc il est inutile d'essayer de l'utiliser dans votre propre code.

Obtenir des fichiers

Jusqu'à présent, Christian nous a montré comment instancier une classe.

Une liste complète des méthodes de la classe peut être trouvée sur la page de documentation officielle.

Dans ce cast, nous allons apprendre la méthode filesListFolder(). Elle accepte un dossier et commence à retourner le contenu du dossier.

dbx.filesListFolder({  
  path: ''  
}).then(res => console.log(res))

// pour des résultats complets de console.log, visitez :  
// [https://scrimba.com/p/pnyeEhr/cGvvanuy](https://scrimba.com/p/pnyeEhr/cGvvanuy)

Il y a quelques choses à garder à l'esprit lorsque nous utilisons filesListFolder() :

  • elle retourne une promesse.
  • pour spécifier un chemin racine, nous devons spécifier une chaîne vide '' et non '/'

Rendre les fichiers

Dans cette leçon, Christian va nous montrer comment rendre les fichiers que nous obtenons de filesListFolder() du cast précédent. Il nous fournira un code de base en JavaScript vanilla pour nous aider à démarrer, afin que nous puissions nous concentrer sur la partie la plus intéressante de cette leçon : le rendu des fichiers.

Image

Écrivons la fonction renderFiles(), ensemble avec Christian.

Nous devons ajouter à fileListElem.innerHTML tous les fichiers triés par ordre alphabétique, en veillant à ce que nous placions les dossiers en premier. Nous mappons ensuite chaque dossier et fichier à un <li> et les joignons en utilisant join('') pour éviter de rendre un tableau au lieu d'une chaîne.

Image

Et voilà, notre liste de fichiers rendue !

Image

Rendre les miniatures

Dans ce screencast, Cristian va se concentrer sur le rendu des miniatures et nous allons voir comment obtenir des miniatures réelles de Dropbox dans la leçon suivante.

Nous allons modifier notre fonction renderFiles(). Dans la partie .map, nous pouvons vérifier si la miniature existe pour un fichier et l'utiliser, sinon, utiliser une miniature par défaut. Gardez à l'esprit que les dossiers n'ont pas de miniatures.

Les images par défaut seront fournies sous forme de chaînes base64, et si vous suivez le cours dans votre propre éditeur, vous pouvez visiter le cast pour les copier.

Image

Super, maintenant nous avons des miniatures par défaut rendues et dans le prochain cast, Christian va nous montrer comment rendre des miniatures réelles que nous pouvons obtenir de l'API Dropbox.

Image

Obtenir des miniatures

Comme Christian l'a promis dans la dernière leçon, nous allons maintenant rendre des miniatures réelles que nous pouvons obtenir de l'API Dropbox pour les fichiers qui en ont.

Nous allons ajouter et créer getThumbnails() à notre méthode updateFiles().

const updateFiles = files => {  
  state.files = [...state.files, ...files]  
  renderFiles()  
  getThumbnails(files)  
}

Pour obtenir des miniatures, nous pouvons utiliser un point de terminaison API existant :

// [http://dropbox.github.io/dropbox-sdk-js/Dropbox.html](http://dropbox.github.io/dropbox-sdk-js/Dropbox.html)

dbx.filesGetThumbnailBatch({  
  entries: [{  
    path: '',  
    // taille préférée pour une miniature  
    size: 'w32h32'  
  }]  
})

Et voici la fonction getThumbnails() terminée :

Image

Si vous êtes intéressé par une visite détaillée ou souhaitez copier le code, n'hésitez pas à sauter dans le cast lui-même.

Async / Await

Jusqu'à présent, nous avons utilisé deux appels API qui retournent des promesses. Nous les avons résolus en utilisant .then() et dans ce screencast, Christian va nous montrer comment nous pouvons les refactoriser en utilisant async/await.

Pour utiliser async/await, nous déclarons async devant notre fonction et await avant notre appel API.

Regardons comment nous pouvons refactoriser notre fonction init().

const init = async () => {  
  const res = await dbx.filesListFolder({  
    path: '',  
    limit: 20  
  })  
  updateFiles(res.entries)  
}

Et maintenant, refactorisons getThumbnail() :

Image

Le curseur

Dans ce cast, nous allons apprendre le concept de curseur de Dropbox.

En termes d'API simples, le curseur est une indication de l'endroit où nous en sommes parmi nos fichiers.

Par exemple, vous avez 100 fichiers, et vous avez demandé les 20 premiers. Le curseur se déplacera vers le 21ème fichier et vous indiquera que vous avez plus de fichiers à télécharger via le champ has_more: true. Plus vous demandez de fichiers, plus le curseur avance jusqu'à ce qu'il vous indique qu'il n'y a plus de fichiers restants avec has_more: false.

Voici à quoi cela ressemblerait en réalité.

Image

Vous pouvez utiliser la chaîne de curseur pour indiquer à l'API où se trouve le curseur, afin de ne pas recevoir les fichiers que vous avez déjà.

Dans la prochaine leçon, Christian nous montrera comment nous pouvons appliquer ce concept à notre application et utiliser le curseur pour obtenir plus de fichiers.

Obtenir plus de fichiers

Mettons à jour la méthode init() pour charger d'autres fichiers s'il y en a, en vérifiant la propriété has_more sur notre réponse.

const init = async () => {  
  const res = await dbx.filesListFolder({  
    path: '',  
    limit: 20  
  })  
  updateFiles(res.entries)  
  if (res.has_more) {  
    getMoreFiles(res.cursor, more => updateFiles(more.entries))  
  }  
}

Nous pouvons améliorer l'expérience utilisateur en ajoutant un message de chargement lorsque d'autres fichiers doivent être chargés.

const loadingElem = document.querySelector('.js-loading')

const init = async () => {  
  const res = await dbx.filesListFolder({  
    path: '',  
    limit: 20  
  })  
  updateFiles(res.entries)  
  if (res.has_more) {  
    loadingElem.classList.remove('hidden')  
    getMoreFiles(res.cursor, more => updateFiles(more.entries))  
    loadingElem.classList.add('hidden')  
  } else {  
    loadingElem.classList.add('hidden')  
  }  
}

Maintenant, nous pouvons implémenter la fonction getMoreFiles().

const getMoreFiles = async (cursor, cb) => {  
  const res = await dbx.filesListFolderContinue({ cursor })

// nous vérifions si le callback est fourni et si oui - nous l'appelons  
  if (cb) cb(res)

if (res.has_more) {  
    // s'il y a plus de fichiers, appelez getMoreFiles de manière récursive,  
    // en fournissant le même callback.  
    await getMoreFiles(res.cursor, cb)  
  }  
}

Changer le chemin du fichier

Wow, nous avons écrit un code vraiment amazing jusqu'à présent.

Une chose qui serait vraiment cool, c'est si nous n'étions pas si restreints au chemin racine tout le temps.

C'est exactement ce que nous allons apprendre dans ce cast.

Pour nous aider à démarrer, Christian a apporté quelques modifications au HTML et au CSS de notre application et le principal changement est le champ Chemin du dossier. C'est là que l'utilisateur peut spécifier le dossier auquel il souhaite accéder.

Image

Nous pouvons faire fonctionner cela en écoutant l'événement de soumission sur rootPathForm, lorsque l'utilisateur nous indique où il veut aller. Nous vérifions ensuite leur entrée et empêchons les erreurs de base, comme l'utilisation de la mauvaise casse pour le nom d'un dossier. Nous devons également stocker la valeur de rootPathInput dans notre state pour pouvoir la réutiliser dans le reste de notre application.

Image

Déplacer des fichiers

Dans cette leçon, nous allons implémenter la fonction principale de notre application : la capacité à organiser nos fichiers dans des dossiers, en fonction de la date de modification.

Tout d'abord, nous devons ajouter un peu de code organisationnel, pour nous assurer que notre fonctionnalité principale est agréable pour nos utilisateurs avant d'implémenter moveFilesToDatedFolders().

const organizeBtn = document.querySelector('.js-organize-btn')

organizeBtn.addEventListener('click', async e => {  
  const originalMsg = e.target.innerHTML  
  e.target.disabled = true  
  e.target.innerHTML = 'Working...'  
  await moveFilesToDatedFolders()  
  e.target.disabled = false  
  e.target.innerHTML = originalMsg  
})

Ensuite, implémentons moveFilesToDatedFolders() qui utilisera filesMoveBatchV2() de Dropbox.

// Implémentation de base de l'API.   
dbx.filesMoveBatchV2({  
  entries: [{  
    from_path: 'some_folder',  
    to_path: 'some_other_folder'  
  }]  
})

Bien sûr, nous n'allons pas utiliser de valeurs codées en dur dans notre application et Christian nous montrera comment générer le tableau entries, organisé par la valeur de la date de modification, afin que les noms des dossiers soient basés sur ces dates.

Image

Afficher les fichiers déplacés

Dans le screencast précédent, Christian nous a montré comment déplacer des fichiers dans leurs propres dossiers en fonction de la date de modification et dans ce cast, nous apprenons comment affiner la fonctionnalité existante.

filesMoveBatchV2() retourne l'une des deux choses : success si l'appel a immédiatement réussi, et cela peut arriver si nous demandons à déplacer un ou deux fichiers. Cependant, il est plus probable qu'il retourne un objet avec une propriété async_job_id, et cela signifie que votre appel est en cours d'exécution.

Dans ce cas, nous pouvons utiliser filesMoveBatchCheckV2() pour vérifier l'achèvement de notre travail jusqu'à ce qu'il soit complet, ou en d'autres termes, qu'il ne soit pas in_progress.

C'est là que Christian nous aide à réécrire moveFilesToDatedFolders() en utilisant une boucle do while, dont la caractéristique clé est qu'elle est garantie d'être exécutée au moins une fois.

Image

Il y a maintenant une chose de plus que nous devons faire : après que l'utilisateur ait déplacé les fichiers, nous voulons lui montrer à quoi ressemble le nouvel état, sans qu'il ait à actualiser la page.

Nous voulons essentiellement réutiliser ce morceau de fonctionnalité :

state.files = []  
loadingElem.classList.remove('hidden')  
init()

Et extrayons-le dans une nouvelle méthode reset().

Image

Nous pouvons maintenant voir la fonctionnalité en action. Cliquez sur 'Organiser' et regardez tous nos fichiers être magiquement placés dans des dossiers. Voici un gif de son fonctionnement :

Image

Conclusion

C'est la fin du cours, alors félicitations pour l'avoir terminé ! Vous devriez maintenant être familier avec la façon d'obtenir des fichiers et des miniatures, et comment déplacer des fichiers en utilisant l'API Dropbox. De plus, vous aurez appris plusieurs concepts ES6.

Enfin, je tiens à remercier Dropbox pour avoir sponsorisé et payé cet article et le cours lui-même. Cela aide Scrimba à garder les lumières allumées et nous permet de créer plus de contenu gratuit pour notre communauté tout au long de 2019.

Bonne programmation :)