From bdd2759641a70ff767f5d7bf7ef07bbc464f1430 Mon Sep 17 00:00:00 2001
From: Nawfel Senoussi <nawfelsen@mbp-de-nawfel.home>
Date: Sun, 31 Mar 2024 12:50:28 +0200
Subject: [PATCH] manage proposal resolve and close

---
 index.ts                                      |  4 +-
 src/features/proposal/closeProposal.ts        |  6 ++-
 src/features/proposal/resolveProposal.ts      |  6 ++-
 .../association/associationHandlers.ts        | 20 +++++---
 src/handlers/proposal/proposalHandlers.ts     | 51 ++++++++++++++++---
 src/handlers/roleHandlers.ts                  |  3 ++
 src/handlers/token/tokenHandlers.ts           |  6 ++-
 src/services/association.service.ts           |  5 +-
 src/services/proposal.service.ts              |  8 +--
 src/services/token.service.ts                 |  2 +-
 src/types/Proposal.ts                         |  1 +
 src/utils/getRole.ts                          |  6 +--
 .../association/associationHandlers.spec.ts   | 16 +++---
 test/handlers/roleHandlers.spec.ts            |  8 +++
 14 files changed, 99 insertions(+), 43 deletions(-)

diff --git a/index.ts b/index.ts
index e188a3b..c2f9288 100644
--- a/index.ts
+++ b/index.ts
@@ -42,7 +42,7 @@ program.command('main')
     while (true) {
       const role: Role = await getRole(tezos)
 
-      console.log(chalk.bgBlue(`\nVous êtes connecté en tant que ${role}\n`))
+      console.log(`Vous êtes connecté en tant que ${chalk.bgBlue(role)}\n`)
 
       const questions = [
         {
@@ -65,7 +65,7 @@ program.command('main')
         case 'ADHERENT':
           // VOTER POUR UNE PROPOSITION
           // CLOTURER ET RESOUDRE LES PROPOSITIONS DONT IL EST LE CREATEUR
-          questions[0].choices = ['Faire une proposition', 'Créer un token']
+          questions[0].choices = ['Faire une proposition', 'Voir les propositions', 'Créer un token']
 
           if (await handleHasToken(tezos)) { questions[0].choices.push('Bruler des tokens') }
 
diff --git a/src/features/proposal/closeProposal.ts b/src/features/proposal/closeProposal.ts
index da2edd1..3307d31 100644
--- a/src/features/proposal/closeProposal.ts
+++ b/src/features/proposal/closeProposal.ts
@@ -1,11 +1,13 @@
 import { type TezosToolkit } from '@taquito/taquito'
 import chalk from 'chalk'
-import { handleGetProposals, handleCloseProposal } from '../../handlers/proposal/proposalHandlers.js'
+import { handleGetOpenProposals, handleCloseProposal } from '../../handlers/proposal/proposalHandlers.js'
 
 async function closeProposal (tezos: TezosToolkit): Promise<void> {
-  await handleGetProposals(tezos).then(async (response) => {
+  await handleGetOpenProposals(tezos).then(async (response) => {
     const proposalsByTitle: string[] = response
 
+    if (response.length === 0) throw new Error("Aucune proposition n'est ouverte")
+
     await handleCloseProposal(proposalsByTitle, tezos).then(() => {
       console.log(chalk.bgGreenBright('\nVous avez clôturé la proposition !!\n'))
     }).catch((error) => {
diff --git a/src/features/proposal/resolveProposal.ts b/src/features/proposal/resolveProposal.ts
index 0f1703c..7477c59 100644
--- a/src/features/proposal/resolveProposal.ts
+++ b/src/features/proposal/resolveProposal.ts
@@ -1,11 +1,13 @@
 import { type TezosToolkit } from '@taquito/taquito'
 import chalk from 'chalk'
-import { handleGetProposals, handleResolveProposal } from '../../handlers/proposal/proposalHandlers.js'
+import { handleGetSolvableProposals, handleResolveProposal } from '../../handlers/proposal/proposalHandlers.js'
 
 async function resolveProposal (tezos: TezosToolkit): Promise<void> {
-  await handleGetProposals(tezos).then(async (response) => {
+  await handleGetSolvableProposals(tezos).then(async (response) => {
     const proposalsByTitle: string[] = response
 
+    if (response.length === 0) throw new Error("Aucune proposition n'est résoluble")
+
     await handleResolveProposal(proposalsByTitle, tezos).then(() => {
       console.log(chalk.bgGreenBright('\nVous avez résolue la proposition !!\n'))
     }).catch((error) => {
diff --git a/src/handlers/association/associationHandlers.ts b/src/handlers/association/associationHandlers.ts
index b5fac02..7bbfc67 100644
--- a/src/handlers/association/associationHandlers.ts
+++ b/src/handlers/association/associationHandlers.ts
@@ -57,7 +57,8 @@ async function handleCreateAssociation (tezos: TezosToolkit): Promise<void> {
   try {
     await createAssociation(association, tezos)
   } catch (error) {
-    throw new Error(`${error.lastError.with.string}`)
+    const errorMessage = error.lastError.with.string ? error.lastError.with.string : 'Unknown error occurred'
+    throw new Error(`${errorMessage}`)
   }
 }
 
@@ -86,20 +87,23 @@ async function handleJoinAssociation (associations: string[], tezos: TezosToolki
   try {
     await joinAssociation(associationName, tezos)
   } catch (error) {
-    throw new Error(`${error.lastError.with.string}`)
+    const errorMessage = error.lastError.with.string ? error.lastError.with.string : 'Unknown error occurred'
+    throw new Error(`${errorMessage}`)
   }
 }
 
 /**
  * Handles the process of listing associations.
  * @param {TezosToolkit} tezos - The TezosToolkit instance used for blockchain operations.
- * @returns {Promise<string[]>} A promise with a string of association name.
+ * @returns {Promise<string[]>} A promise with a list of string of association name.
  */
 async function handleGetAssociations (tezos: TezosToolkit): Promise<string[]> {
   try {
-    return await getAssociations(tezos)
+    const associations = await getAssociations(tezos)
+    return associations.map(association => association.name)
   } catch (error) {
-    throw new Error(`${error.lastError.with.string}`)
+    const errorMessage = error.lastError.with.string ? error.lastError.with.string : 'Unknown error occurred'
+    throw new Error(`${errorMessage}`)
   }
 }
 
@@ -128,7 +132,8 @@ async function handleGetAssociationDetails (associations: string[], tezos: Tezos
   try {
     return await getAssociationDetails(associationName, tezos)
   } catch (error) {
-    throw new Error(`${error.lastError.with.string}`)
+    const errorMessage = error.lastError.with.string ? error.lastError.with.string : 'Unknown error occurred'
+    throw new Error(`${errorMessage}`)
   }
 }
 
@@ -141,7 +146,8 @@ async function handleIsAdmin (tezos: TezosToolkit): Promise<boolean> {
   try {
     return await isAdminOfAssociation(tezos)
   } catch (error) {
-    throw new Error(`${error}`)
+    const errorMessage = error.lastError.with.string ? error.lastError.with.string : 'Unknown error occurred'
+    throw new Error(`${errorMessage}`)
   }
 }
 
diff --git a/src/handlers/proposal/proposalHandlers.ts b/src/handlers/proposal/proposalHandlers.ts
index 892cfd6..707f5e3 100644
--- a/src/handlers/proposal/proposalHandlers.ts
+++ b/src/handlers/proposal/proposalHandlers.ts
@@ -57,7 +57,8 @@ async function handleCreateProposal (tezos: TezosToolkit): Promise<void> {
   try {
     await createProposal(proposal, tezos)
   } catch (error) {
-    throw new Error(`${error.lastError.with.string}`)
+    const errorMessage = error.lastError.with.string ? error.lastError.with.string : 'Unknown error occurred'
+    throw new Error(`${errorMessage}`)
   }
 }
 
@@ -86,7 +87,8 @@ async function handleResolveProposal (proposals: string[], tezos: TezosToolkit):
   try {
     await resolveProposal(associationName, tezos)
   } catch (error) {
-    throw new Error(`${error.lastError.with.string}`)
+    const errorMessage = error.lastError.with.string ? error.lastError.with.string : 'Unknown error occurred'
+    throw new Error(`${errorMessage}`)
   }
 }
 
@@ -101,7 +103,7 @@ async function handleCloseProposal (proposals: string[], tezos: TezosToolkit): P
     {
       type: 'list',
       name: 'choice',
-      message: 'Quelle proposition voulez-vous clôturé ?',
+      message: 'Quelle proposition voulez-vous clôturer ?',
       choices: proposals
     }
   ]
@@ -115,21 +117,54 @@ async function handleCloseProposal (proposals: string[], tezos: TezosToolkit): P
   try {
     await closeProposal(associationName, tezos)
   } catch (error) {
-    throw new Error(`${error.lastError.with.string}`)
+    const errorMessage = error.lastError.with.string ? error.lastError.with.string : 'Unknown error occurred'
+    throw new Error(`${errorMessage}`)
   }
 }
 
 /**
  * Handles the process of listing proposals.
  * @param {TezosToolkit} tezos - The TezosToolkit instance used for blockchain operations.
- * @returns {Promise<string[]>} A promise with a string of proposal title.
+ * @returns {Promise<Proposal[]>} A promise with a list of proposal title.
  */
 async function handleGetProposals (tezos: TezosToolkit): Promise<string[]> {
   try {
-    return await getProposals(tezos)
+    const proposals: Proposal[] = await getProposals(tezos)
+    return proposals.map(proposal => proposal.title)
   } catch (error) {
-    throw new Error(`${error.lastError.with.string}`)
+    const errorMessage = error.lastError.with.string ? error.lastError.with.string : 'Unknown error occurred'
+    throw new Error(`${errorMessage}`)
   }
 }
 
-export { handleCreateProposal, handleResolveProposal, handleGetProposals, handleCloseProposal }
+/**
+ * Handles the process of listing open proposals.
+ * @param {TezosToolkit} tezos - The TezosToolkit instance used for blockchain operations.
+ * @returns {Promise<string[]>} A promise with a list of open proposal title.
+ */
+async function handleGetOpenProposals (tezos: TezosToolkit): Promise<string[]> {
+  try {
+    const proposals: Proposal[] = await getProposals(tezos)
+    return proposals.filter(proposal => proposal.isOpen).map(proposal => proposal.title)
+  } catch (error) {
+    const errorMessage = error.lastError.with.string ? error.lastError.with.string : 'Unknown error occurred'
+    throw new Error(`${errorMessage}`)
+  }
+}
+
+/**
+ * Handles the process of listing solvable proposals.
+ * @param {TezosToolkit} tezos - The TezosToolkit instance used for blockchain operations.
+ * @returns {Promise<string[]>} A promise with a list of solvable proposal title.
+ */
+async function handleGetSolvableProposals (tezos: TezosToolkit): Promise<string[]> {
+  try {
+    const proposals: Proposal[] = await getProposals(tezos)
+    return proposals.filter(proposal => proposal.approveRate >= 51).map(proposal => proposal.title)
+  } catch (error) {
+    const errorMessage = error.lastError.with.string ? error.lastError.with.string : 'Unknown error occurred'
+    throw new Error(`${errorMessage}`)
+  }
+}
+
+export { handleCreateProposal, handleResolveProposal, handleGetProposals, handleCloseProposal, handleGetOpenProposals, handleGetSolvableProposals }
diff --git a/src/handlers/roleHandlers.ts b/src/handlers/roleHandlers.ts
index 6e6a5d7..095352b 100644
--- a/src/handlers/roleHandlers.ts
+++ b/src/handlers/roleHandlers.ts
@@ -58,6 +58,9 @@ async function handleAdherentChoice (choice: string, tezos: TezosToolkit): Promi
     case 'Créer un token':
       await createToken(tezos)
       break
+    case 'Voir les propositions':
+      await showProposals(tezos)
+      break
     case 'Voir mon portefeuille':
       await showBalance(tezos)
       break
diff --git a/src/handlers/token/tokenHandlers.ts b/src/handlers/token/tokenHandlers.ts
index 8d1df95..edb1f27 100644
--- a/src/handlers/token/tokenHandlers.ts
+++ b/src/handlers/token/tokenHandlers.ts
@@ -38,7 +38,8 @@ async function handleCreateToken (tezos: TezosToolkit): Promise<void> {
   try {
     await createFAToken(nbTokenFungible, tezos)
   } catch (error) {
-    throw new Error(`${error.lastError.with.string}`)
+    const errorMessage = error.lastError.with.string ? error.lastError.with.string : 'Unknown error occurred'
+    throw new Error(`${errorMessage}`)
   }
 }
 
@@ -75,7 +76,8 @@ async function handleBurnToken (tezos: TezosToolkit): Promise<void> {
   try {
     await burnToken(nbTokenToBurn, tezos)
   } catch (error) {
-    throw new Error(`${error.lastError.with.string}`)
+    const errorMessage = error.lastError.with.string ? error.lastError.with.string : 'Unknown error occurred'
+    throw new Error(`${errorMessage}`)
   }
 }
 
diff --git a/src/services/association.service.ts b/src/services/association.service.ts
index 7ebd20e..6a00b3d 100644
--- a/src/services/association.service.ts
+++ b/src/services/association.service.ts
@@ -21,7 +21,6 @@ async function createAssociation (association: Association, tezos: TezosToolkit)
   const op: Operation = await contract.methodsObject.registerAssociation(association).send()
 
   await op.confirmation()
-  console.log(op.hash)
 }
 
 // NEED UPDATE ENTRYPOINT !!
@@ -33,7 +32,7 @@ async function joinAssociation (associationName: string, tezos: TezosToolkit): P
 }
 
 // NEED UPDATE ENTRYPOINT !!
-async function getAssociations (tezos: TezosToolkit): Promise<string[]> {
+async function getAssociations (tezos: TezosToolkit): Promise<Association[]> {
   // const contract = await tezos.contract.at(address)
   // const op: Operation = await contract.methodsObject.getAssociations().send()
 
@@ -41,7 +40,7 @@ async function getAssociations (tezos: TezosToolkit): Promise<string[]> {
   // return op
 
   // MOCK
-  return mockAssociations.map(association => association.name)
+  return mockAssociations
 }
 
 async function getAssociationDetails (associationName: string, tezos: TezosToolkit): Promise<Association> {
diff --git a/src/services/proposal.service.ts b/src/services/proposal.service.ts
index d4a562c..c6caeff 100644
--- a/src/services/proposal.service.ts
+++ b/src/services/proposal.service.ts
@@ -7,7 +7,9 @@ const address = 'KT1QZJzhSPQ89K4eC59tmQYCt44qph7wXoJu'
 const mockProposals: Proposal[] = [
   {
     title: 'Proposal 1',
-    description: 'Ceci est la proposition 1'
+    description: 'Ceci est la proposition 1',
+    isOpen: true,
+    approveRate: 50
   },
   {
     title: 'Proposal 2',
@@ -61,14 +63,14 @@ async function viewVoteInProgressProposal (proposalName: string, tezos: TezosToo
 }
 
 // NEED UPDATE ENTRYPOINT !!
-async function getProposals (tezos: TezosToolkit): Promise<string[]> {
+async function getProposals (tezos: TezosToolkit): Promise<Proposal[]> {
   // const contract = await tezos.contract.at(address)
   // const op: Operation = await contract.methodsObject.resolveProposal(proposalName).send()
 
   // await op.confirmation()
 
   // MOCK
-  return mockProposals.map(association => association.title)
+  return mockProposals
 }
 
 export { createProposal, voteForProposal, viewVoteInProgressProposal, closeProposal, resolveProposal, getProposals }
diff --git a/src/services/token.service.ts b/src/services/token.service.ts
index 983f279..4835dd1 100644
--- a/src/services/token.service.ts
+++ b/src/services/token.service.ts
@@ -30,7 +30,7 @@ async function hasToken (tezos: TezosToolkit): Promise<boolean> {
 
   // await op.confirmation()
 
-  return false
+  return true
 }
 
 export { createFAToken, burnToken, hasToken }
diff --git a/src/types/Proposal.ts b/src/types/Proposal.ts
index cb05777..5bb5781 100644
--- a/src/types/Proposal.ts
+++ b/src/types/Proposal.ts
@@ -4,4 +4,5 @@ export interface Proposal {
   fct?: () => void
   participationRate?: number
   approveRate?: number
+  isOpen?: boolean
 }
diff --git a/src/utils/getRole.ts b/src/utils/getRole.ts
index 5aaaa55..b5bab0f 100644
--- a/src/utils/getRole.ts
+++ b/src/utils/getRole.ts
@@ -1,11 +1,11 @@
 import { type TezosToolkit } from '@taquito/taquito'
 import { type Role } from '../types/Role'
-// import { handleIsAdmin } from '../handlers/association/associationHandlers.js'
+import { handleIsAdmin } from '../handlers/association/associationHandlers.js'
 
 export async function getRole (tezos: TezosToolkit): Promise<Role> {
-  // const isAdmin = await handleIsAdmin(tezos)
+  const isAdmin = await handleIsAdmin(tezos)
 
-  // if (isAdmin) return 'ADMIN'
+  if (isAdmin) return 'ADMIN'
 
   // TEMPORARY
   return 'CONNECTED'
diff --git a/test/handlers/association/associationHandlers.spec.ts b/test/handlers/association/associationHandlers.spec.ts
index f5a9c10..5132f72 100644
--- a/test/handlers/association/associationHandlers.spec.ts
+++ b/test/handlers/association/associationHandlers.spec.ts
@@ -129,16 +129,12 @@ describe('associationHandlers', () => {
         const associations = await handleGetAssociations(mockedTezosToolkit)
 
         expect(getAssociationsSpy).toBeCalledWith(mockedTezosToolkit)
-        expect(associations).toStrictEqual([
-          {
-            name: 'Association 1',
-            description: 'Association 1 description'
-          },
-          {
-            name: 'Association 2',
-            description: 'Association 2 description'
-          }
-        ])
+        expect(associations).toStrictEqual(
+          [
+            'Association 1',
+            'Association 2'
+          ]
+        )
       })
     })
 
diff --git a/test/handlers/roleHandlers.spec.ts b/test/handlers/roleHandlers.spec.ts
index 7eaae2a..755f601 100644
--- a/test/handlers/roleHandlers.spec.ts
+++ b/test/handlers/roleHandlers.spec.ts
@@ -157,6 +157,14 @@ describe('roleHandlers', () => {
       })
     })
 
+    describe('when choice is "Voir les propositions"', () => {
+      it('should call showProposals', async () => {
+        await handleAdminChoice('Voir les propositions', mockedTezosToolkit)
+
+        expect(showProposals).toBeCalled()
+      })
+    })
+
     describe('when choice is invalid', () => {
       it('should log "Choix invalide"', async () => {
         const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
-- 
GitLab