diff --git a/IV-Portal-Franklin/src/App.js b/IV-Portal-Franklin/src/App.js
index f743371d666af9778d7935b94ae8a8dd72280b29..3ae2c7f6bf487972ba3c8854ba1c3ad300a41b88 100644
--- a/IV-Portal-Franklin/src/App.js
+++ b/IV-Portal-Franklin/src/App.js
@@ -19,16 +19,15 @@ import { Stack } from '@mui/material';
 import { Chip } from '@mui/material';
 
 import { TextField } from '@mui/material';
-import SovDropZoneWithRead from './components/SovDropZoneWithRead';
 
 import dropimage from "./assets/dropzone.jpg";
 
-import crypto from "crypto-js";
-import random from "random-string-generator";
 import FingerprintIcon from '@mui/icons-material/Fingerprint';
 import { Tabs, Tab } from '@mui/material';
 
-import WarningAmberIcon from '@mui/icons-material/WarningAmber';
+import * as SSIFileServerHelper from 'ssi-lib/FileServerHelper';
+
+import { ImageListItem } from '@mui/material';
 
 const universalStore = require('./env/universalObject').certifications;
 
@@ -41,16 +40,6 @@ const Item = styled(Paper)(({ theme }) => ({
   color: theme.palette.text.secondary,
 }));
 
-/*
-
-  todo
-
-    Franklin select images from list rather than uploading
-
-    tidy up the code - see code todo's
-
-*/
-
 export default function App() {
   const api_url = env.REACT_APP_AGENT_API;
   const hook_url = env.REACT_APP_AGENT_HOOK;
@@ -75,6 +64,8 @@ export default function App() {
   const [value, setValue] = useState("home");
   const [verified, setVerified] = useState(false);
 
+  const [images, setImages] = useState([]); // image repository list
+
   useEffect(() => {
     if (value !== "home") return;
     setImageFile(undefined);
@@ -84,33 +75,6 @@ export default function App() {
     setVerified(false);
   }, [value]);
 
-  useEffect(() => { console.log("invite was set", invite); }, [invite]);
-
-  // *** todo - WE SHOULD SELECT THE IMAGE FROM THE IMAGE REPO, NOT UPLOAD IT !
-  //          - THERE IS A REPO FUNCTION TO OBTAIN THE HASH TOO, SO NO NEED TO SHA3 IT HERE...
-  useEffect(() => {
-    if (imageFile === undefined) return;
-
-    const reader = new FileReader()
-
-    reader.onabort = () => console.log('file reading was aborted')
-    reader.onerror = () => console.log('file reading has failed')
-    reader.onload = () => {
-      let hex = dropImage.split(",")[1];
-      let hash = crypto.SHA3(hex); // todo *** get the hash from the image repository
-      hash = hash.toString(crypto.enc.Hex);
-
-      let filename = random(20) + imageFile.name;
-      setImageUrl(filename);
-
-      setImageHash(hash);
-      setDropImage(reader.result);
-    }
-
-    reader.readAsDataURL(imageFile);
-
-  }, [imageFile]);
-
   useEffect(SSIConnections.startWebSocketEffect(hook_url, setConnectionResults), []);
   useEffect(SSIConnections.fetchConnectionsEffect(api_url, setConnectionResults), []);
 
@@ -118,8 +82,6 @@ export default function App() {
     if (connectionResults.length === 0) return;
 
     const conn = connectionResults[0]; // todo *** should search presentationResults for a match against INVITATION; don't just get the "latest" one ([0]) - see below also
-    console.log("conn1", conn);
-    console.log(invite);
 
     switch (conn.rfc23_state) {
       case "request-received":
@@ -128,21 +90,29 @@ export default function App() {
         break;
 
       case "response-sent":
-        console.log("trust-ping");
+        console.log("response-sent");
         setTimeout(() => {
           SSIConnections.trustPing(api_url, conn.connection_id);
         }, 1000);
         break;
 
       case "completed":
-        if (!invite.label) return console.log("no invite was found, so the web socket presentation marked as completed was not actioned - it must have been processed earlier.");
+        if (!invite.label) return; // no invite was found, so the web socket presentation marked as completed was not actioned - it must have been processed earlier
         console.log("completed");
 
         let body = {};
         body.connection_id = conn.connection_id;
         body.comment = JSON.stringify({
           flag: "ImageAuthorshipRequest",
-          imgHash: imageHash,
+          imgHash: imageHash, // why do we (i.e. the original webcontroller) send the image hash ??? the holder could use this
+          // to cheat as this comment appears back at Ruth. this would be ok, say, if the only way we can
+          // get the fingerprint back on Franklin is via the credential, without relying on what Ruth says... 
+
+          // i think the imageHash is sent to Ruth purely for reference purposes because Ruth only
+          // sends back (presents) "credential -> referent" so presumably Aries uses this reference
+          // to check the "coment" fields automatically ????
+
+          // need to look into this more !
         });
         body.proof_request = { name: "Proof Request" };
         body.proof_request.nonce = "1"; // temporary nonce
@@ -160,7 +130,6 @@ export default function App() {
         body.proof_request.version = "1.0";
         SSIPresentationsHelper.sendPresentationRequest(api_url, body);
 
-        console.log("presentation request was sent");
         break;
     }
   }, [connectionResults]);
@@ -168,7 +137,6 @@ export default function App() {
   useEffect(() => {
     if (presentationResults.length === 0) return;
     const conn = presentationResults[0]; // todo *** should search presentationResults for a match against INVITATION; don't just get the "latest" one ([0]) - see below also
-    console.log("conn2", conn);
 
     switch (conn.state) {
       case "presentation_received":
@@ -194,7 +162,7 @@ export default function App() {
       return;
     }
 
-    const status = conn.presentation.requested_proof.revealed_attrs.additionalProp1.raw === JSON.parse(conn.presentation_request_dict.comment).imgHash;
+    const status = conn.presentation.requested_proof.revealed_attrs.additionalProp1.raw === imageHash;
 
     setVerified(status ? IMAGE_VERIFIED : IMAGE_NOT_VERIFIED);
   }
@@ -209,55 +177,60 @@ export default function App() {
   useEffect(SSIPresentationsHelper.startWebSocketEffect(hook_url, setPresentationResults), []);
 
   const Interaction = (props) => {
-    console.log(props.details);
-
-    var flag, geolocation, imgHash, imgTimestamp, imgUrl, macAddress;
-    var presentation_received, verified;
-    var proposal_received, offer_sent, request_received, credential_issued, done, issue_credential;
+    var geolocation, imgHash, imgTimestamp, imgUrl, macAddress;
     var image_url;
     var presentation = false;
     var credential = false;
 
-    var attributes;
+    // *** THE BELOW COMMENTED CODE IS JUST WHAT WAS COPIED OVER FROM A DIFFERENT PORTAL
+    //     WE MAY FIND IT USEFUL AS REFERENCE WHEN UPDATING THIS PORTAL'S VIEW-CREDENTIAL
+    //     CREDIT-CARD COMPONENT LATER - THEN JUST DELETE IT...
 
-    // let attributes = props.details.cred_preview.attributes;
+    // var flag;
+    // var presentation_received;
+    // var proposal_received, offer_sent, request_received, credential_issued, done, issue_credential;
+    // var attributes;
 
-    var state = props.details.state;
-    if (!state) state = "Invalid";
+    // // let attributes = props.details.cred_preview.attributes;
 
-    const cred_ex_id = props.details.cred_ex_id;
-    console.log("details", props.details);
+    // var state = props.details.state;
+    // if (!state) state = "Invalid";
 
-    if (props.details.presentation_proposal_dict) {  // is this a presentation ?
+    // const cred_ex_id = props.details.cred_ex_id;
 
-      attributes = JSON.parse(props.details.presentation_proposal_dict.comment);
+    // if (props.details.presentation_proposal_dict) {  // is this a presentation ?
 
-      flag = attributes.flag;
-      geolocation = attributes.geolocation;
-      imgHash = attributes.imgHash;
-      imgTimestamp = attributes.imgTimestamp;
-      imgUrl = attributes.imgUrl;
-      macAddress = attributes.macAddress;
+    //   attributes = JSON.parse(props.details.presentation_proposal_dict.comment);
 
-      image_url = FILE_SERVER_URL + "uploads/" + imgUrl;
+    //   flag = attributes.flag;
+    //   geolocation = attributes.geolocation;
+    //   imgHash = attributes.imgHash;
+    //   imgTimestamp = attributes.imgTimestamp;
+    //   imgUrl = attributes.imgUrl;
+    //   macAddress = attributes.macAddress;
 
-      // presentation states
-      proposal_received = state === "proposal_received"; // _ NOT - here >>> is this internal to ACA-Py ??? not sure...
-      presentation_received = state === "presentation_received"; // as above
-      verified = state === "verified";
-      console.log("state", state);
+    //   image_url = FILE_SERVER_URL + "uploads/" + imgUrl;
 
-      presentation = true;
-    }
-    else { // is this a ... what other states are viewed on the thoday side ?
-      proposal_received = state === "proposal-received";
-      offer_sent = state === "offer-sent";
-      request_received = state === "request-received";
-      credential_issued = state === "credential-issued";
-      done = state === "done";
-
-      credential = true;
-    }
+    //   // presentation states
+    //   proposal_received = state === "proposal_received"; // "_" NOT "-" here --> is this internal to ACA-Py ??? not sure...
+    //   presentation_received = state === "presentation_received"; // as above
+    //   verified = state === "verified";
+
+    //   console.log("presentation", props.details);
+
+    //   presentation = true;
+    // }
+    // else { // is this a ... what other states are viewed on the thoday side ?
+    //   proposal_received = state === "proposal-received";
+    //   offer_sent = state === "offer-sent";
+    //   request_received = state === "request-received";
+    //   credential_issued = state === "credential-issued";
+    //   done = state === "done";
+
+    //   console.log("other", props.details);
+
+    //   credential = true;
+    // }
 
     return (
       <Box m={3}>
@@ -336,9 +309,10 @@ export default function App() {
         <Button
           style={{ marginTop: 40, backgroundColor: "blue" }}
           variant="contained"
-          onClick={() => {
+          onClick={async () => {
             setValue("details");
             createNewInvite(); // create a new invite before switching tabs
+            setImages(await SSIFileServerHelper.getImagesFromRegistry(FILE_SERVER_URL)); // update the image list
           }}>
           CONTINUE
         </Button>
@@ -348,36 +322,58 @@ export default function App() {
 
   function renderDetailsTab() {
     return <div>
-      <Typography mt={3} style={{ fontWeight: "bold" }}>Enter photograh details</Typography>
-      <Box
-        component="form"
-        sx={{
-          '& > :not(style)': { m: 1, width: '95%' },
-        }}
-        noValidate
-        autoComplete="off"
-        m={1}
-      >
-        <TextField id="standard-basic" label="Name" variant="standard" />
-        <TextField id="standard-basic" label="Description" variant="standard" />
-        <Stack direction="row" m={1}>
-          <Box m={2}><WarningAmberIcon style={{ color: "red", fontSize: 50 }} /></Box>
-          <Box m={2}>
-            <Typography color="red">Upload is just for development. User should select from image repo list instead...</Typography>
-          </Box>
+      <Typography mt={3} style={{ fontWeight: "bold" }}>Select your photograph</Typography>
+      <Paper style={{ overflow: 'auto' }} elevation={0}>
+        <Stack direction="row">
+          {images.map((image, index) => (
+            <ImageListItem key={"image" + index}>
+              <Box m={1}
+                sx={{ width: 200 }}>
+                <img
+                  src={FILE_SERVER_URL + "imageRegistry/" + image}
+                  width="100%"
+                  onClick={async () => {
+                    let hash = (await SSIFileServerHelper.imageHash(FILE_SERVER_URL, image)).data.message;
+                    setImageHash(hash);
+                    setImageFile(image);
+                  }}
+                />
+              </Box>
+            </ImageListItem>
+          ))}
         </Stack>
-        <SovDropZoneWithRead
-          dropImage={dropImage}
-          setDropImage={setDropImage}
-          setImageFile={setImageFile}
-        />
-      </Box>
-      {
-        imageHash && <Box mt={3}>
-          <Chip style={{ margin: 10, width: 500, backgroundColor: 'transparent' }} icon={<FingerprintIcon fontSize="large" />} label={imageHash} >
-          </Chip>
-        </Box>
-      }
+      </Paper>
+      <Typography mt={3} style={{ fontWeight: "bold" }}>Enter photograph details</Typography>
+      <Grid container>
+        <Grid xs={3}>
+          <Box mt={4}>
+            {imageFile && <Paper style={{ overflow: 'auto', maxWidth: "100%" }} elevation={0}>
+              <img src={FILE_SERVER_URL + "imageRegistry/" + imageFile} width="100%" />
+            </Paper>}
+          </Box>
+        </Grid>
+        <Grid xs={9}>
+          <Box
+            component="form"
+            sx={{
+              '& > :not(style)': { m: 1, width: '95%' },
+            }}
+            noValidate
+            autoComplete="off"
+            m={1}
+          >
+            <TextField id="standard-basic" label="Name" variant="standard" />
+            <TextField id="standard-basic" label="Description" variant="standard" />
+          </Box>
+        </Grid>
+        <Grid xs={12}>
+          {
+            imageHash &&
+            <Chip style={{ margin: 10, width: 500, backgroundColor: 'transparent' }} icon={<FingerprintIcon fontSize="large" />} label={imageHash} >
+            </Chip>
+          }
+        </Grid>
+      </Grid>
       <Box align="center" m="auto">
         <Button
           style={{ marginTop: 40, backgroundColor: "blue" }}
@@ -401,7 +397,7 @@ export default function App() {
             <CircularProgress />
             <Typography ml={2} mt={1}>Awaiting presentation</Typography>
           </Stack>}
-        {verified && <Typography ml={2} mt={1}>Your photograph was verified !</Typography>}
+        {verified && <Typography ml={2} mt={1}>Processing...</Typography>}
       </Stack>
     </div>;
   }
@@ -409,7 +405,7 @@ export default function App() {
   function renderDoneTab() {
     return <div>
       {verified === IMAGE_VERIFIED && <Typography mt={3}>Your photograph was successfully verified !</Typography>}
-      {verified === IMAGE_NOT_VERIFIED && <Typography mt={3}>The image does not match the hash requested by Franklin News</Typography>}
+      {verified === IMAGE_NOT_VERIFIED && <Typography mt={3}>The presented image hash does not match the hash of the image you selected in Franklin News.</Typography>}
       {verified === IMAGE_ERROR && <Typography mt={3}>Something went wrong with the verification process, please try again.</Typography>}
       <Box align="center" m="auto">
         <Button
diff --git a/IV-Portal-Franklin/src/components/SovQRCodeDrag.js b/IV-Portal-Franklin/src/components/SovQRCodeDrag.js
index decf649a269ab70b9405e33758d75f48018fa003..212e0561b1fe73cc4fa53421210b89104a54536c 100644
--- a/IV-Portal-Franklin/src/components/SovQRCodeDrag.js
+++ b/IV-Portal-Franklin/src/components/SovQRCodeDrag.js
@@ -3,9 +3,7 @@ import QRCode from 'qrcode.react';
 export default function QRCodeDrag(props) {
 
     function dragStart(e) {
-        console.log("Drag and drop started:\n\nData: ", props.data)
         e.dataTransfer.setData("text", JSON.stringify(props.data));
-        console.log(JSON.stringify(props.data));
         return true;
     }
     
diff --git a/IV-Portal-Franklin/src/env/env.js b/IV-Portal-Franklin/src/env/env.js
index 05aa6315f7f4dca42e888b95b527fc2160f55af6..55a0b60075e86ecd417c6989cba7897eb532f8c1 100644
--- a/IV-Portal-Franklin/src/env/env.js
+++ b/IV-Portal-Franklin/src/env/env.js
@@ -97,7 +97,5 @@ export default class Env {
 
         // ws.close();
         // wsCC.close();
-
-        console.log("Completed");
     }
 }