Skip to content

Commit

Permalink
feat: Add contact edit menu
Browse files Browse the repository at this point in the history
This menu is contextualized according to the current form field.
It can be displayed via a new button in the list
of ambiguous data, or naturally for the last and first name fields.
  • Loading branch information
Merkur39 committed Sep 10, 2024
1 parent c5793f2 commit 98d6701
Show file tree
Hide file tree
Showing 11 changed files with 626 additions and 17 deletions.
48 changes: 48 additions & 0 deletions apps/browser/src/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -1707,15 +1707,27 @@
"firstName": {
"message": "First name"
},
"givenName": {
"message": "First name"
},
"middleName": {
"message": "Middle name"
},
"additionalName": {
"message": "Middle name"
},
"lastName": {
"message": "Last name"
},
"familyName": {
"message": "Last name"
},
"fullName": {
"message": "Full name"
},
"displayName": {
"message": "Full name"
},
"identityName": {
"message": "Full name"
},
Expand Down Expand Up @@ -3184,6 +3196,30 @@
"fax": {
"message": "Fax"
},
"cellHome": {
"message": "Cell (perso)"
},
"cellWork": {
"message": "Cell (pro)"
},
"voiceHome": {
"message": "Voice (perso)"
},
"voiceWork": {
"message": "Voice (pro)"
},
"faxHome": {
"message": "Fax (perso)"
},
"faxWork": {
"message": "Fax (pro)"
},
"none": {
"message": "Aucun"
},
"empty_name": {
"message": "Aucun nom"
},
"loggingInOn": {
"message": "Logging in on"
},
Expand Down Expand Up @@ -4512,5 +4548,17 @@
},
"empty_ambiguous_address": {
"message": "No address found"
},
"newAddress": {
"message": "New address"
},
"newPhone": {
"message": "New phone"
},
"newEmail": {
"message": "New email"
},
"newName": {
"message": "New name"
}
}
51 changes: 51 additions & 0 deletions apps/browser/src/_locales/fr/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -1710,15 +1710,27 @@
"firstName": {
"message": "Prénom"
},
"givenName": {
"message": "Prénom"
},
"middleName": {
"message": "Deuxième prénom"
},
"additionalName": {
"message": "Deuxième prénom"
},
"lastName": {
"message": "Nom de famille"
},
"familyName": {
"message": "Nom de famille"
},
"fullName": {
"message": "Nom et prénom"
},
"displayName": {
"message": "Nom et prénom"
},
"identityName": {
"message": "Nom complet"
},
Expand Down Expand Up @@ -3187,6 +3199,33 @@
"fax": {
"message": "Fax"
},
"cellHome": {
"message": "Mobile (perso)"
},
"cellWork": {
"message": "Mobile (pro)"
},
"voiceHome": {
"message": "Fixe (perso)"
},
"voiceWork": {
"message": "Fixe (pro)"
},
"faxHome": {
"message": "Fax (perso)"
},
"faxWork": {
"message": "Fax (pro)"
},
"none": {
"message": "Aucun"
},
"empty_name": {
"message": "Aucun nom"
},
"label": {
"message": "Libellé"
},
"loggingInOn": {
"message": "Connexion sur"
},
Expand Down Expand Up @@ -4524,5 +4563,17 @@
},
"empty_ambiguous_address": {
"message": "Aucune adresse enregistrée"
},
"newAddress": {
"message": "Nouvelle adresse"
},
"newPhone": {
"message": "Nouveau téléphone"
},
"newEmail": {
"message": "Nouvel email"
},
"newName": {
"message": "Nouveau nom"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ export type InlineMenuListPortMessageHandlers = {
updateAutofillInlineMenuListHeight: ({ message, port }: PortOnMessageHandlerParams) => void;
redirectToCozy: ({ message, port }: PortOnMessageHandlerParams) => void;
handleMenuListUpdate: ({ message, port }: PortOnMessageHandlerParams) => void;
editInlineMenuCipher: ({ message, port }: PortOnMessageHandlerParams) => void;
};

export interface OverlayBackground {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2704,7 +2704,7 @@ describe("OverlayBackground", () => {
);
});

it("copies the cipher's totp code to the clipboard after filling", async () => {
fit("copies the cipher's totp code to the clipboard after filling", async () => {
const cipher1 = mock<CipherView>({ id: "inline-menu-cipher-1" });
overlayBackground["inlineMenuCiphers"] = new Map([["inline-menu-cipher-1", cipher1]]);
overlayBackground["pageDetailsForTab"][sender.tab.id] = new Map([
Expand All @@ -2718,7 +2718,7 @@ describe("OverlayBackground", () => {

sendPortMessage(listMessageConnectorSpy, {
command: "fillAutofillInlineMenuCipher",
inlineMenuCipherId: "inline-menu-cipher-2",
inlineMenuCipherId: "inline-menu-cipher-1",
portKey,
});
await flushPromises();
Expand Down
86 changes: 82 additions & 4 deletions apps/browser/src/autofill/background/overlay.background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ import { nameToColor } from "cozy-ui/transpiled/react/Avatar/helpers";
import { CozyClientService } from "../../popup/services/cozyClient.service";
import { AmbiguousContactFieldName, AmbiguousContactFieldValue } from "src/autofill/types";
import { COZY_ATTRIBUTES_MAPPING } from "../../../../../libs/cozy/mapping";
import { getCozyValue } from "../../../../../libs/cozy/getCozyValue";
/* eslint-enable */
/* end Cozy imports */

Expand Down Expand Up @@ -170,6 +171,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
inlineMenuSearchContact: ({ message }) => this.searchContacts(message),
redirectToCozy: ({ message }) => this.redirectToCozy(message),
handleMenuListUpdate: ({ message, port }) => this.handleMenuListUpdate(message, port),
editInlineMenuCipher: ({ message }) => this.editInlineMenuCipher(message),
// Cozy customization end
addNewVaultItem: ({ message, port }) => this.getNewVaultItemDetails(message, port),
viewSelectedCipher: ({ message, port }) => this.viewSelectedCipher(message, port),
Expand All @@ -194,6 +196,24 @@ export class OverlayBackground implements OverlayBackgroundInterface {
this.initOverlayEventObservables();
}

// Cozy customization
private editInlineMenuCipher = async (message: OverlayPortMessage) => {
const { inlineMenuCipherId } = message;
const client = await this.cozyClientService.getClientInstance();
const cipher = this.inlineMenuCiphers.get(inlineMenuCipherId);

const { data: contact } = (await client.query(Q(CONTACTS_DOCTYPE).getById(cipher.id), {
executeFromStore: true,
})) as { data: IOCozyContact };

this.inlineMenuListPort?.postMessage({
command: "editContactFields",
inlineMenuCipherId,
contactName: contact.displayName,
});
};
// Cozy customization end

// Cozy customization
private handleMenuListUpdate = async (message: OverlayPortMessage, port: chrome.runtime.Port) => {
const { inlineMenuCipherId } = message;
Expand Down Expand Up @@ -338,7 +358,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
// Cozy customization end

// Cozy customization; Add contacts first in the list for fixes a bug when opening the iniline menu on an ambiguous field after the first autofill
return this.cardAndIdentityCiphers
return this.cardAndIdentityCiphers.size > 0
? Array.from(this.cardAndIdentityCiphers).concat(...cipherViews)
: cipherViews;
// Cozy customization end
Expand Down Expand Up @@ -886,7 +906,29 @@ export class OverlayBackground implements OverlayBackgroundInterface {
message: OverlayPortMessage,
port: chrome.runtime.Port,
) {
const { ambiguousValue, fieldHtmlIDToFill } = message;
const { ambiguousValue, fieldHtmlIDToFill, inlineMenuCipherId } = message;
const client = await this.cozyClientService.getClientInstance();
const cipher = this.inlineMenuCiphers.get(inlineMenuCipherId);

const { data: contact } = (await client.query(Q(CONTACTS_DOCTYPE).getById(cipher.id), {
executeFromStore: true,
})) as { data: IOCozyContact };

const value = await getCozyValue({
client,
contactId: cipher.id,
fieldQualifier: this.focusedFieldData?.fieldQualifier,
});

if (!value) {
this.inlineMenuListPort?.postMessage({
command: "createEmptyNameList",
inlineMenuCipherId,
contactName: contact.displayName,
});
return;
}

this.fillInlineMenuCipher(message, port, ambiguousValue, fieldHtmlIDToFill);
}

Expand All @@ -906,7 +948,8 @@ export class OverlayBackground implements OverlayBackgroundInterface {
const ambiguousContactFields = getAmbiguousFieldsContact(ambiguousContactFieldNames, contact);

const isFocusedFieldAmbigous = ambiguousContactFieldNames.includes(
COZY_ATTRIBUTES_MAPPING[this.focusedFieldData?.fieldQualifier].name as AmbiguousContactFieldName,
COZY_ATTRIBUTES_MAPPING[this.focusedFieldData?.fieldQualifier]
.name as AmbiguousContactFieldName,
);
const hasMultipleAmbiguousValueInSameField = Object.values(ambiguousContactFields).some(
(item) => item.length > 1,
Expand All @@ -915,7 +958,8 @@ export class OverlayBackground implements OverlayBackgroundInterface {
// On an ambiguous form field, the associated contact values are kept.
const ambiguousFormFieldsOfFocusedField = Object.fromEntries(
Object.entries(ambiguousContactFields).filter(
([fieldName]) => fieldName === COZY_ATTRIBUTES_MAPPING[this.focusedFieldData?.fieldQualifier].name,
([fieldName]) =>
fieldName === COZY_ATTRIBUTES_MAPPING[this.focusedFieldData?.fieldQualifier].name,
),
);
// On an unambiguous form field, we keep only the multiple values of an ambiguous contact field.
Expand Down Expand Up @@ -947,6 +991,20 @@ export class OverlayBackground implements OverlayBackgroundInterface {
fieldHtmlIDToFill,
});
} else {
const value = await getCozyValue({
client,
contactId: cipher.id,
fieldQualifier: this.focusedFieldData?.fieldQualifier,
});

if (!value) {
this.inlineMenuListPort?.postMessage({
command: "editContactFields",
inlineMenuCipherId,
contactName: contact.displayName,
});
return;
}
this.fillInlineMenuCipher(message, port);
}
}
Expand Down Expand Up @@ -1546,10 +1604,30 @@ export class OverlayBackground implements OverlayBackgroundInterface {
empty_ambiguous_email: this.i18nService.translate("empty_ambiguous_email"),
empty_ambiguous_phone: this.i18nService.translate("empty_ambiguous_phone"),
empty_ambiguous_address: this.i18nService.translate("empty_ambiguous_address"),
empty_name: this.i18nService.translate("empty_name"),
new: this.i18nService.translate("new"),
address: this.i18nService.translate("address"),
phone: this.i18nService.translate("phone"),
email: this.i18nService.translate("email"),
cellHome: this.i18nService.translate("cellHome"),
cellWork: this.i18nService.translate("cellWork"),
voiceHome: this.i18nService.translate("voiceHome"),
voiceWork: this.i18nService.translate("voiceWork"),
faxHome: this.i18nService.translate("faxHome"),
faxWork: this.i18nService.translate("faxWork"),
none: this.i18nService.translate("none"),
name: this.i18nService.translate("name"),
newAddress: this.i18nService.translate("newAddress"),
newPhone: this.i18nService.translate("newPhone"),
newEmail: this.i18nService.translate("newEmail"),
newName: this.i18nService.translate("newName"),
givenName: this.i18nService.translate("givenName"),
additionalName: this.i18nService.translate("additionalName"),
familyName: this.i18nService.translate("familyName"),
displayName: this.i18nService.translate("displayName"),
label: this.i18nService.translate("label"),
save: this.i18nService.translate("save"),
cancel: this.i18nService.translate("cancel"),
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@ export type AutofillInlineMenuListWindowMessageHandlers = {
}: {
message: UpdateAutofillInlineMenuListAmbiguousMessage;
}) => void;
editContactFields: ({
message,
}: {
message: UpdateAutofillInlineMenuListAmbiguousMessage;
}) => void;
createEmptyNameList: ({
message,
}: {
message: UpdateAutofillInlineMenuListAmbiguousMessage;
}) => void;
// Cozy customization end
focusAutofillInlineMenuList: () => void;
};
Loading

0 comments on commit 98d6701

Please sign in to comment.