Compare commits
20
Commits
d8f7a41bdd
...
caf02056ab
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
caf02056ab | ||
|
|
4b26d5ed40 | ||
|
|
885d9932e2 | ||
|
|
f6c355498b | ||
|
|
455f0f5c67 | ||
|
|
e99370683b | ||
|
|
9fb1551bef | ||
|
|
8d40301ddf | ||
|
|
93fb2b8bca | ||
|
|
97178a603f | ||
|
|
f13c1d21c0 | ||
|
|
7e28c8693c | ||
|
|
c95181b0cf | ||
|
|
b2c5051d31 | ||
|
|
6e46a8dfda | ||
|
|
99c9a698a0 | ||
|
|
aa5e9ef5c7 | ||
|
|
4f6d617829 | ||
|
|
05c5ffa43c | ||
|
|
9d7bfec6d6 |
+6
-2
@@ -63,6 +63,11 @@ label.small {
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
label.large {
|
||||
color: #1e88e5;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
img.avatar {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -1754,9 +1759,8 @@ video {
|
||||
.call-party.peer .caller-name.inactive {
|
||||
position: absolute;
|
||||
font-size: larger;
|
||||
left: 50%;
|
||||
left: 1rem;
|
||||
bottom: 0.5rem;
|
||||
transform: translateX(-50%);
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Generated
+547
-547
File diff suppressed because it is too large
Load Diff
+3
-3
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "tinode-webapp",
|
||||
"description": "Tinode messenger for the web",
|
||||
"version": "0.21.0-rc2",
|
||||
"version": "0.21.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/tinode/example-react-js.git"
|
||||
@@ -9,7 +9,7 @@
|
||||
"scripts": {
|
||||
"start": "echo 'Read installation instructions'",
|
||||
"build": "npm run vers && npm run build:css && npm run extract && npm run build:i18n && npm run build:prod && npm run build:dev",
|
||||
"clean": "rm umd/* && rm css/base.min.css && rm i18n.min/*",
|
||||
"clean": "rm umd/* && rm css/base.min.css && rm src/i18n.min/*",
|
||||
"build:css": "postcss css/base.css > css/base.min.css",
|
||||
"build:dev": "webpack --mode development",
|
||||
"build:prod": "webpack --mode production",
|
||||
@@ -70,7 +70,7 @@
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-intl": "^6.2.1",
|
||||
"tinode-sdk": "^0.21.0-rc2",
|
||||
"tinode-sdk": "^0.21.0",
|
||||
"webm-duration-fix": "^1.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+51
-9
@@ -102,7 +102,7 @@
|
||||
"defaultMessage": "Add another",
|
||||
"description": "Call to action [+ add another]",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
"obsolete": true
|
||||
},
|
||||
"button_add_members": {
|
||||
"translation": "Mitglieder hinzufügen",
|
||||
@@ -579,8 +579,8 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"label_user_contacts": {
|
||||
"translation": "Kontakte:",
|
||||
"defaultMessage": "Contacts:",
|
||||
"translation": "Kontakte",
|
||||
"defaultMessage": "Contacts",
|
||||
"description": "Label for user contacts",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
@@ -1227,7 +1227,7 @@
|
||||
"defaultMessage": "confirm",
|
||||
"description": "Validate credentail call to action",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
"obsolete": true
|
||||
},
|
||||
"description_editing_placeholder": {
|
||||
"translation": "Beschreibung (optional)",
|
||||
@@ -1307,8 +1307,8 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"password_reset_email_sent": {
|
||||
"translation": "Eine E-Mail wurde an {email} gesendet. Folgen Sie den Anweisungen in der E-Mail, um Ihr Passwort zurückzusetzen.",
|
||||
"defaultMessage": "An email with security code has been sent to {email}. Enter the code below.",
|
||||
"translation": "Eine E-Mail mit Sicherheitscode wurde gesendet.",
|
||||
"defaultMessage": "An email with security code has been sent.",
|
||||
"description": "Notification that the email with password reset instructions has been sent",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
@@ -1436,7 +1436,7 @@
|
||||
"defaultMessage": "Phone number or email",
|
||||
"description": "Placeholer for phone or email",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
"obsolete": true
|
||||
},
|
||||
"cred_confirmed_successfully": {
|
||||
"translation": "Erfolgreich bestätigt",
|
||||
@@ -1586,8 +1586,8 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"password_reset_sms_sent": {
|
||||
"translation": "Eine Textnachricht mit Sicherheitscode wurde an {phone} gesendet. Geben Sie den Code unten ein.",
|
||||
"defaultMessage": "A text message with security code has been sent to {phone}. Enter the code below.",
|
||||
"translation": "Eine SMS mit einem Sicherheitscode wurde gesendet.",
|
||||
"defaultMessage": "A text message with security code has been sent.",
|
||||
"description": "Notification that the SMS with password reset instructions has been sent",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
@@ -1598,5 +1598,47 @@
|
||||
"description": "Error message",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"current_email": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Current email",
|
||||
"description": "Label for old email",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"current_phone": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Current phone number",
|
||||
"description": "Label for old phone",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"new_email": {
|
||||
"translation": "",
|
||||
"defaultMessage": "New email",
|
||||
"description": "Prompt for entering a new email",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"new_phone_number": {
|
||||
"translation": "",
|
||||
"defaultMessage": "New phone number",
|
||||
"description": "Prompt for entering a new telephone number",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"change_email": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Change email",
|
||||
"description": "Prompt to change current email",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"change_phonel": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Change phone number",
|
||||
"description": "Prompt to change current phone number",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
+51
-9
@@ -102,7 +102,7 @@
|
||||
"defaultMessage": "Add another",
|
||||
"description": "Call to action [+ add another]",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
"obsolete": true
|
||||
},
|
||||
"button_add_members": {
|
||||
"translation": "Add members",
|
||||
@@ -579,8 +579,8 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"label_user_contacts": {
|
||||
"translation": "Contacts:",
|
||||
"defaultMessage": "Contacts:",
|
||||
"translation": "Contacts",
|
||||
"defaultMessage": "Contacts",
|
||||
"description": "Label for user contacts",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
@@ -1227,7 +1227,7 @@
|
||||
"defaultMessage": "confirm",
|
||||
"description": "Validate credentail call to action",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
"obsolete": true
|
||||
},
|
||||
"description_editing_placeholder": {
|
||||
"translation": "Optional description",
|
||||
@@ -1314,8 +1314,8 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"password_reset_email_sent": {
|
||||
"translation": "An email has been sent to {email}. Follow the directions in the email to reset your password.",
|
||||
"defaultMessage": "An email with security code has been sent to {email}. Enter the code below.",
|
||||
"translation": "An email with security code has been sent.",
|
||||
"defaultMessage": "An email with security code has been sent.",
|
||||
"description": "Notification that the email with password reset instructions has been sent",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
@@ -1436,7 +1436,7 @@
|
||||
"defaultMessage": "Phone number or email",
|
||||
"description": "Placeholer for phone or email",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
"obsolete": true
|
||||
},
|
||||
"cred_confirmed_successfully": {
|
||||
"translation": "Confirmed successfully",
|
||||
@@ -1586,8 +1586,8 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"password_reset_sms_sent": {
|
||||
"translation": "A text message with security code has been sent to {phone}. Enter the code below.",
|
||||
"defaultMessage": "A text message with security code has been sent to {phone}. Enter the code below.",
|
||||
"translation": "A text message with security code has been sent.",
|
||||
"defaultMessage": "A text message with security code has been sent.",
|
||||
"description": "Notification that the SMS with password reset instructions has been sent",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
@@ -1598,5 +1598,47 @@
|
||||
"description": "Error message",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"current_email": {
|
||||
"translation": "Current email",
|
||||
"defaultMessage": "Current email",
|
||||
"description": "Label for old email",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"current_phone": {
|
||||
"translation": "Current phone number",
|
||||
"defaultMessage": "Current phone number",
|
||||
"description": "Label for old phone",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"new_email": {
|
||||
"translation": "New email",
|
||||
"defaultMessage": "New email",
|
||||
"description": "Prompt for entering a new email",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"new_phone_number": {
|
||||
"translation": "New phone number",
|
||||
"defaultMessage": "New phone number",
|
||||
"description": "Prompt for entering a new telephone number",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"change_email": {
|
||||
"translation": "Change email",
|
||||
"defaultMessage": "Change email",
|
||||
"description": "Prompt to change current email",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"change_phonel": {
|
||||
"translation": "Change phone number",
|
||||
"defaultMessage": "Change phone number",
|
||||
"description": "Prompt to change current phone number",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
+51
-9
@@ -102,7 +102,7 @@
|
||||
"defaultMessage": "Add another",
|
||||
"description": "Call to action [+ add another]",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
"obsolete": true
|
||||
},
|
||||
"button_add_members": {
|
||||
"translation": "Añadir miembros",
|
||||
@@ -579,8 +579,8 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"label_user_contacts": {
|
||||
"translation": "Contactos:",
|
||||
"defaultMessage": "Contacts:",
|
||||
"translation": "Contactos",
|
||||
"defaultMessage": "Contacts",
|
||||
"description": "Label for user contacts",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
@@ -1220,7 +1220,7 @@
|
||||
"defaultMessage": "confirm",
|
||||
"description": "Validate credentail call to action",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
"obsolete": true
|
||||
},
|
||||
"description_editing_placeholder": {
|
||||
"translation": "Descripción (opcional)",
|
||||
@@ -1307,8 +1307,8 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"password_reset_email_sent": {
|
||||
"translation": "Se ha enviado un correo electrónico a {email}. Siga las instrucciones del correo electrónico para restablecer su contraseña.",
|
||||
"defaultMessage": "An email with security code has been sent to {email}. Enter the code below.",
|
||||
"translation": "Se ha enviado un correo electrónico con el código de seguridad.",
|
||||
"defaultMessage": "An email with security code has been sent.",
|
||||
"description": "Notification that the email with password reset instructions has been sent",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
@@ -1436,7 +1436,7 @@
|
||||
"defaultMessage": "Phone number or email",
|
||||
"description": "Placeholer for phone or email",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
"obsolete": true
|
||||
},
|
||||
"cred_confirmed_successfully": {
|
||||
"translation": "Confirmado con éxito",
|
||||
@@ -1586,8 +1586,8 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"password_reset_sms_sent": {
|
||||
"translation": "Se ha enviado un mensaje de texto con un código de seguridad a {phone}. Ingresa el código a continuación.",
|
||||
"defaultMessage": "A text message with security code has been sent to {phone}. Enter the code below.",
|
||||
"translation": "Se ha enviado un mensaje de texto con un código de seguridad.",
|
||||
"defaultMessage": "A text message with security code has been sent.",
|
||||
"description": "Notification that the SMS with password reset instructions has been sent",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
@@ -1598,5 +1598,47 @@
|
||||
"description": "Error message",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"current_email": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Current email",
|
||||
"description": "Label for old email",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"current_phone": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Current phone number",
|
||||
"description": "Label for old phone",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"new_email": {
|
||||
"translation": "",
|
||||
"defaultMessage": "New email",
|
||||
"description": "Prompt for entering a new email",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"new_phone_number": {
|
||||
"translation": "",
|
||||
"defaultMessage": "New phone number",
|
||||
"description": "Prompt for entering a new telephone number",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"change_email": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Change email",
|
||||
"description": "Prompt to change current email",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"change_phonel": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Change phone number",
|
||||
"description": "Prompt to change current phone number",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
+27
-15
@@ -59,10 +59,6 @@
|
||||
"defaultMessage": "Blocked contacts ({count})",
|
||||
"description": "Blocked contacts link"
|
||||
},
|
||||
"button_add_another": {
|
||||
"defaultMessage": "Add another",
|
||||
"description": "Call to action [+ add another]"
|
||||
},
|
||||
"button_add_members": {
|
||||
"defaultMessage": "Add members",
|
||||
"description": "Flat button [Add members] (to topic)"
|
||||
@@ -159,6 +155,14 @@
|
||||
"defaultMessage": "Cannot initiate file upload.",
|
||||
"description": "Generic error messagewhen attachment fails"
|
||||
},
|
||||
"change_email": {
|
||||
"defaultMessage": "Change email",
|
||||
"description": "Prompt to change current email"
|
||||
},
|
||||
"change_phonel": {
|
||||
"defaultMessage": "Change phone number",
|
||||
"description": "Prompt to change current phone number"
|
||||
},
|
||||
"channel": {
|
||||
"defaultMessage": "channel",
|
||||
"description": "Subtitle shown for channels in MessagesView instead of last seen"
|
||||
@@ -207,6 +211,14 @@
|
||||
"defaultMessage": "Your registration email",
|
||||
"description": "Placeholder for entering email"
|
||||
},
|
||||
"current_email": {
|
||||
"defaultMessage": "Current email",
|
||||
"description": "Label for old email"
|
||||
},
|
||||
"current_phone": {
|
||||
"defaultMessage": "Current phone number",
|
||||
"description": "Label for old phone"
|
||||
},
|
||||
"delete_account": {
|
||||
"defaultMessage": "Delete account",
|
||||
"description": "Title for delete account warning"
|
||||
@@ -453,7 +465,7 @@
|
||||
"description": "Label for WS/WSS connection type in SettingsView"
|
||||
},
|
||||
"label_user_contacts": {
|
||||
"defaultMessage": "Contacts:",
|
||||
"defaultMessage": "Contacts",
|
||||
"description": "Label for user contacts"
|
||||
},
|
||||
"label_user_id": {
|
||||
@@ -616,6 +628,10 @@
|
||||
"defaultMessage": "+{overflow} more",
|
||||
"description": "Shown in MessagesView title bar when the number of online subscribers exceeds MAX_ONLINE_IN_TOPIC"
|
||||
},
|
||||
"new_email": {
|
||||
"defaultMessage": "New email",
|
||||
"description": "Prompt for entering a new email"
|
||||
},
|
||||
"new_message_prompt": {
|
||||
"defaultMessage": "New message",
|
||||
"description": "Prompt in send message field"
|
||||
@@ -624,6 +640,10 @@
|
||||
"defaultMessage": "Enter new password",
|
||||
"description": "Placeholder for entering new password"
|
||||
},
|
||||
"new_phone_number": {
|
||||
"defaultMessage": "New phone number",
|
||||
"description": "Prompt for entering a new telephone number"
|
||||
},
|
||||
"no_connection": {
|
||||
"defaultMessage": "No connection",
|
||||
"description": "Warning that the user is offline."
|
||||
@@ -669,11 +689,11 @@
|
||||
"description": "Placeholder/prompt for entering password"
|
||||
},
|
||||
"password_reset_email_sent": {
|
||||
"defaultMessage": "An email with security code has been sent to {email}. Enter the code below.",
|
||||
"defaultMessage": "An email with security code has been sent.",
|
||||
"description": "Notification that the email with password reset instructions has been sent"
|
||||
},
|
||||
"password_reset_sms_sent": {
|
||||
"defaultMessage": "A text message with security code has been sent to {phone}. Enter the code below.",
|
||||
"defaultMessage": "A text message with security code has been sent.",
|
||||
"description": "Notification that the SMS with password reset instructions has been sent"
|
||||
},
|
||||
"password_unchanged_prompt": {
|
||||
@@ -732,10 +752,6 @@
|
||||
"defaultMessage": "phone",
|
||||
"description": "Dative case of 'phone', i.e. 'phone' in 'by phone'"
|
||||
},
|
||||
"phone_or_email_prompt": {
|
||||
"defaultMessage": "Phone number or email",
|
||||
"description": "Placeholer for phone or email"
|
||||
},
|
||||
"private_editing_placeholder": {
|
||||
"defaultMessage": "Visible to you only",
|
||||
"description": "Placeholder for editing 'private'"
|
||||
@@ -907,9 +923,5 @@
|
||||
"user_not_found": {
|
||||
"defaultMessage": "Not found",
|
||||
"description": "In place of a user's full name when the user is not found."
|
||||
},
|
||||
"validate_credential_action": {
|
||||
"defaultMessage": "confirm",
|
||||
"description": "Validate credentail call to action"
|
||||
}
|
||||
}
|
||||
|
||||
+51
-9
@@ -102,7 +102,7 @@
|
||||
"defaultMessage": "Add another",
|
||||
"description": "Call to action [+ add another]",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
"obsolete": true
|
||||
},
|
||||
"button_add_members": {
|
||||
"translation": "Ajouter des membres",
|
||||
@@ -579,8 +579,8 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"label_user_contacts": {
|
||||
"translation": "Contacts :",
|
||||
"defaultMessage": "Contacts:",
|
||||
"translation": "Contacts",
|
||||
"defaultMessage": "Contacts",
|
||||
"description": "Label for user contacts",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
@@ -1227,7 +1227,7 @@
|
||||
"defaultMessage": "confirm",
|
||||
"description": "Validate credentail call to action",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
"obsolete": true
|
||||
},
|
||||
"description_editing_placeholder": {
|
||||
"translation": "Description facultative",
|
||||
@@ -1314,8 +1314,8 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"password_reset_email_sent": {
|
||||
"translation": "Un email a été envoyé à {email}. Suivez les instructions du mail pour remettre à zéro votre mot de passe.",
|
||||
"defaultMessage": "An email with security code has been sent to {email}. Enter the code below.",
|
||||
"translation": "Un e-mail avec code de sécurité a été envoyé.",
|
||||
"defaultMessage": "An email with security code has been sent.",
|
||||
"description": "Notification that the email with password reset instructions has been sent",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
@@ -1436,7 +1436,7 @@
|
||||
"defaultMessage": "Phone number or email",
|
||||
"description": "Placeholer for phone or email",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
"obsolete": true
|
||||
},
|
||||
"cred_confirmed_successfully": {
|
||||
"translation": "Confirmé avec succès",
|
||||
@@ -1586,8 +1586,8 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"password_reset_sms_sent": {
|
||||
"translation": "Un SMS avec un code de sécurité a été envoyé à {phone}. Saisissez le code ci-dessous.",
|
||||
"defaultMessage": "A text message with security code has been sent to {phone}. Enter the code below.",
|
||||
"translation": "Un message texte avec un code de sécurité a été envoyé.",
|
||||
"defaultMessage": "A text message with security code has been sent.",
|
||||
"description": "Notification that the SMS with password reset instructions has been sent",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
@@ -1598,5 +1598,47 @@
|
||||
"description": "Error message",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"current_email": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Current email",
|
||||
"description": "Label for old email",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"current_phone": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Current phone number",
|
||||
"description": "Label for old phone",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"new_email": {
|
||||
"translation": "",
|
||||
"defaultMessage": "New email",
|
||||
"description": "Prompt for entering a new email",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"new_phone_number": {
|
||||
"translation": "",
|
||||
"defaultMessage": "New phone number",
|
||||
"description": "Prompt for entering a new telephone number",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"change_email": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Change email",
|
||||
"description": "Prompt to change current email",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"change_phonel": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Change phone number",
|
||||
"description": "Prompt to change current phone number",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
+52
-10
@@ -102,7 +102,7 @@
|
||||
"defaultMessage": "Add another",
|
||||
"description": "Call to action [+ add another]",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
"obsolete": true
|
||||
},
|
||||
"button_add_members": {
|
||||
"translation": "회원추가",
|
||||
@@ -579,8 +579,8 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"label_user_contacts": {
|
||||
"translation": "연락처: ",
|
||||
"defaultMessage": "Contacts:",
|
||||
"translation": "연락처",
|
||||
"defaultMessage": "Contacts",
|
||||
"description": "Label for user contacts",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
@@ -1220,7 +1220,7 @@
|
||||
"defaultMessage": "confirm",
|
||||
"description": "Validate credentail call to action",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
"obsolete": true
|
||||
},
|
||||
"description_editing_placeholder": {
|
||||
"translation": "설명(선택 사항)",
|
||||
@@ -1307,8 +1307,8 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"password_reset_email_sent": {
|
||||
"translation": "이메일이 {email}(으)로 전송되었습니다. 이메일의 지침에 따라 비밀번호를 재설정하세요.",
|
||||
"defaultMessage": "An email with security code has been sent to {email}. Enter the code below.",
|
||||
"translation": "보안 코드가 포함된 이메일이 전송되었습니다.",
|
||||
"defaultMessage": "An email with security code has been sent.",
|
||||
"description": "Notification that the email with password reset instructions has been sent",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
@@ -1436,7 +1436,7 @@
|
||||
"defaultMessage": "Phone number or email",
|
||||
"description": "Placeholer for phone or email",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
"obsolete": true
|
||||
},
|
||||
"cred_confirmed_successfully": {
|
||||
"translation": "성공적으로 확인됨",
|
||||
@@ -1544,7 +1544,7 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"menu_item_audio_call": {
|
||||
"translation": "부르다",
|
||||
"translation": "전화",
|
||||
"defaultMessage": "Call",
|
||||
"description": "Start audio call",
|
||||
"missing": false,
|
||||
@@ -1586,8 +1586,8 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"password_reset_sms_sent": {
|
||||
"translation": "보안 코드가 포함된 문자 메시지가 {phone}로 전송되었습니다. 아래 코드를 입력하세요.",
|
||||
"defaultMessage": "A text message with security code has been sent to {phone}. Enter the code below.",
|
||||
"translation": "보안 코드가 포함된 문자 메시지가 전송되었습니다.",
|
||||
"defaultMessage": "A text message with security code has been sent.",
|
||||
"description": "Notification that the SMS with password reset instructions has been sent",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
@@ -1598,5 +1598,47 @@
|
||||
"description": "Error message",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"current_email": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Current email",
|
||||
"description": "Label for old email",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"current_phone": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Current phone number",
|
||||
"description": "Label for old phone",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"new_email": {
|
||||
"translation": "",
|
||||
"defaultMessage": "New email",
|
||||
"description": "Prompt for entering a new email",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"new_phone_number": {
|
||||
"translation": "",
|
||||
"defaultMessage": "New phone number",
|
||||
"description": "Prompt for entering a new telephone number",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"change_email": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Change email",
|
||||
"description": "Prompt to change current email",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"change_phonel": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Change phone number",
|
||||
"description": "Prompt to change current phone number",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
+51
-9
@@ -102,7 +102,7 @@
|
||||
"defaultMessage": "Add another",
|
||||
"description": "Call to action [+ add another]",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
"obsolete": true
|
||||
},
|
||||
"button_add_members": {
|
||||
"translation": "Adaugă persoane",
|
||||
@@ -579,8 +579,8 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"label_user_contacts": {
|
||||
"translation": "Contacte:",
|
||||
"defaultMessage": "Contacts:",
|
||||
"translation": "Contacte",
|
||||
"defaultMessage": "Contacts",
|
||||
"description": "Label for user contacts",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
@@ -1220,7 +1220,7 @@
|
||||
"defaultMessage": "confirm",
|
||||
"description": "Validate credentail call to action",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
"obsolete": true
|
||||
},
|
||||
"description_editing_placeholder": {
|
||||
"translation": "Descriere (opțional)",
|
||||
@@ -1307,8 +1307,8 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"password_reset_email_sent": {
|
||||
"translation": "Un e-mail a fost trimis către {email}. Urmați instrucțiunile din e-mail pentru a vă reseta parola.",
|
||||
"defaultMessage": "An email with security code has been sent to {email}. Enter the code below.",
|
||||
"translation": "A fost trimis un e-mail cu cod de securitate.",
|
||||
"defaultMessage": "An email with security code has been sent.",
|
||||
"description": "Notification that the email with password reset instructions has been sent",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
@@ -1436,7 +1436,7 @@
|
||||
"defaultMessage": "Phone number or email",
|
||||
"description": "Placeholer for phone or email",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
"obsolete": true
|
||||
},
|
||||
"cred_confirmed_successfully": {
|
||||
"translation": "Confirmat cu succes",
|
||||
@@ -1586,8 +1586,8 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"password_reset_sms_sent": {
|
||||
"translation": "Un mesaj text cu cod de securitate a fost trimis la {phone}. Introduceți codul de mai jos.",
|
||||
"defaultMessage": "A text message with security code has been sent to {phone}. Enter the code below.",
|
||||
"translation": "A fost trimis un mesaj text cu cod de securitate.",
|
||||
"defaultMessage": "A text message with security code has been sent.",
|
||||
"description": "Notification that the SMS with password reset instructions has been sent",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
@@ -1598,5 +1598,47 @@
|
||||
"description": "Error message",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"current_email": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Current email",
|
||||
"description": "Label for old email",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"current_phone": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Current phone number",
|
||||
"description": "Label for old phone",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"new_email": {
|
||||
"translation": "",
|
||||
"defaultMessage": "New email",
|
||||
"description": "Prompt for entering a new email",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"new_phone_number": {
|
||||
"translation": "",
|
||||
"defaultMessage": "New phone number",
|
||||
"description": "Prompt for entering a new telephone number",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"change_email": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Change email",
|
||||
"description": "Prompt to change current email",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"change_phonel": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Change phone number",
|
||||
"description": "Prompt to change current phone number",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
+51
-9
@@ -102,7 +102,7 @@
|
||||
"defaultMessage": "Add another",
|
||||
"description": "Call to action [+ add another]",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
"obsolete": true
|
||||
},
|
||||
"button_add_members": {
|
||||
"translation": "Добавить",
|
||||
@@ -579,8 +579,8 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"label_user_contacts": {
|
||||
"translation": "Конакты:",
|
||||
"defaultMessage": "Contacts:",
|
||||
"translation": "Конакты",
|
||||
"defaultMessage": "Contacts",
|
||||
"description": "Label for user contacts",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
@@ -1220,7 +1220,7 @@
|
||||
"defaultMessage": "confirm",
|
||||
"description": "Validate credentail call to action",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
"obsolete": true
|
||||
},
|
||||
"description_editing_placeholder": {
|
||||
"translation": "Описание (не обязательно)",
|
||||
@@ -1307,8 +1307,8 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"password_reset_email_sent": {
|
||||
"translation": "Сообщение было отправлено на адрес {email}. Следуйте инструкциям в сообщении, чтобы изменить пароль.",
|
||||
"defaultMessage": "An email with security code has been sent to {email}. Enter the code below.",
|
||||
"translation": "Сообщение было отправлено на указанный email.",
|
||||
"defaultMessage": "An email with security code has been sent.",
|
||||
"description": "Notification that the email with password reset instructions has been sent",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
@@ -1436,7 +1436,7 @@
|
||||
"defaultMessage": "Phone number or email",
|
||||
"description": "Placeholer for phone or email",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
"obsolete": true
|
||||
},
|
||||
"cred_confirmed_successfully": {
|
||||
"translation": "Подтверждено успешно",
|
||||
@@ -1586,8 +1586,8 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"password_reset_sms_sent": {
|
||||
"translation": "SMS с защитным кодом отправлено на {phone}. Введите код ниже.",
|
||||
"defaultMessage": "A text message with security code has been sent to {phone}. Enter the code below.",
|
||||
"translation": "SMS с защитным кодом отправлен.",
|
||||
"defaultMessage": "A text message with security code has been sent.",
|
||||
"description": "Notification that the SMS with password reset instructions has been sent",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
@@ -1598,5 +1598,47 @@
|
||||
"description": "Error message",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"current_email": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Current email",
|
||||
"description": "Label for old email",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"current_phone": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Current phone number",
|
||||
"description": "Label for old phone",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"new_email": {
|
||||
"translation": "",
|
||||
"defaultMessage": "New email",
|
||||
"description": "Prompt for entering a new email",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"new_phone_number": {
|
||||
"translation": "",
|
||||
"defaultMessage": "New phone number",
|
||||
"description": "Prompt for entering a new telephone number",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"change_email": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Change email",
|
||||
"description": "Prompt to change current email",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"change_phonel": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Change phone number",
|
||||
"description": "Prompt to change current phone number",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
+53
-11
@@ -102,7 +102,7 @@
|
||||
"defaultMessage": "Add another",
|
||||
"description": "Call to action [+ add another]",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
"obsolete": true
|
||||
},
|
||||
"button_add_members": {
|
||||
"translation": "新增成員",
|
||||
@@ -579,8 +579,8 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"label_user_contacts": {
|
||||
"translation": "聯絡人:",
|
||||
"defaultMessage": "Contacts:",
|
||||
"translation": "聯絡人",
|
||||
"defaultMessage": "Contacts",
|
||||
"description": "Label for user contacts",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
@@ -593,10 +593,10 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"label_wire_transport": {
|
||||
"translation": "Wire transport:",
|
||||
"translation": "",
|
||||
"defaultMessage": "Wire transport:",
|
||||
"description": "Label for wire transport selection in SettingsView",
|
||||
"missing": false,
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"label_you": {
|
||||
@@ -1220,7 +1220,7 @@
|
||||
"defaultMessage": "confirm",
|
||||
"description": "Validate credentail call to action",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
"obsolete": true
|
||||
},
|
||||
"description_editing_placeholder": {
|
||||
"translation": "說明(可選)",
|
||||
@@ -1307,8 +1307,8 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"password_reset_email_sent": {
|
||||
"translation": "一封電子郵件已發送至 {email}。按照電子郵件中的說明重置密碼。",
|
||||
"defaultMessage": "An email with security code has been sent to {email}. Enter the code below.",
|
||||
"translation": "已發送一封帶有安全代碼的電子郵件。",
|
||||
"defaultMessage": "An email with security code has been sent.",
|
||||
"description": "Notification that the email with password reset instructions has been sent",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
@@ -1436,7 +1436,7 @@
|
||||
"defaultMessage": "Phone number or email",
|
||||
"description": "Placeholer for phone or email",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
"obsolete": true
|
||||
},
|
||||
"cred_confirmed_successfully": {
|
||||
"translation": "確認成功",
|
||||
@@ -1586,8 +1586,8 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"password_reset_sms_sent": {
|
||||
"translation": "帶有安全碼的短信已發送至{phone}。請在下方輸入密碼。",
|
||||
"defaultMessage": "A text message with security code has been sent to {phone}. Enter the code below.",
|
||||
"translation": "已發送帶有安全代碼的短信。",
|
||||
"defaultMessage": "A text message with security code has been sent.",
|
||||
"description": "Notification that the SMS with password reset instructions has been sent",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
@@ -1598,5 +1598,47 @@
|
||||
"description": "Error message",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"current_email": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Current email",
|
||||
"description": "Label for old email",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"current_phone": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Current phone number",
|
||||
"description": "Label for old phone",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"new_email": {
|
||||
"translation": "",
|
||||
"defaultMessage": "New email",
|
||||
"description": "Prompt for entering a new email",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"new_phone_number": {
|
||||
"translation": "",
|
||||
"defaultMessage": "New phone number",
|
||||
"description": "Prompt for entering a new telephone number",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"change_email": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Change email",
|
||||
"description": "Prompt to change current email",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"change_phonel": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Change phone number",
|
||||
"description": "Prompt to change current phone number",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
+51
-9
@@ -102,7 +102,7 @@
|
||||
"defaultMessage": "Add another",
|
||||
"description": "Call to action [+ add another]",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
"obsolete": true
|
||||
},
|
||||
"button_add_members": {
|
||||
"translation": "添加成员",
|
||||
@@ -579,8 +579,8 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"label_user_contacts": {
|
||||
"translation": "往来:",
|
||||
"defaultMessage": "Contacts:",
|
||||
"translation": "往来",
|
||||
"defaultMessage": "Contacts",
|
||||
"description": "Label for user contacts",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
@@ -1220,7 +1220,7 @@
|
||||
"defaultMessage": "confirm",
|
||||
"description": "Validate credentail call to action",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
"obsolete": true
|
||||
},
|
||||
"description_editing_placeholder": {
|
||||
"translation": "说明(可选)",
|
||||
@@ -1307,8 +1307,8 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"password_reset_email_sent": {
|
||||
"translation": "一封电子邮件已发送至 {email}。按照电子邮件中的说明重置密码。",
|
||||
"defaultMessage": "An email with security code has been sent to {email}. Enter the code below.",
|
||||
"translation": "已发送一封带有安全代码的电子邮件。",
|
||||
"defaultMessage": "An email with security code has been sent.",
|
||||
"description": "Notification that the email with password reset instructions has been sent",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
@@ -1436,7 +1436,7 @@
|
||||
"defaultMessage": "Phone number or email",
|
||||
"description": "Placeholer for phone or email",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
"obsolete": true
|
||||
},
|
||||
"cred_confirmed_successfully": {
|
||||
"translation": "确认成功",
|
||||
@@ -1586,8 +1586,8 @@
|
||||
"obsolete": false
|
||||
},
|
||||
"password_reset_sms_sent": {
|
||||
"translation": "带有安全码的短信已发送至{phone}。请在下方输入密码。",
|
||||
"defaultMessage": "A text message with security code has been sent to {phone}. Enter the code below.",
|
||||
"translation": "已发送带有安全代码的短信。",
|
||||
"defaultMessage": "A text message with security code has been sent.",
|
||||
"description": "Notification that the SMS with password reset instructions has been sent",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
@@ -1598,5 +1598,47 @@
|
||||
"description": "Error message",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"current_email": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Current email",
|
||||
"description": "Label for old email",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"current_phone": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Current phone number",
|
||||
"description": "Label for old phone",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"new_email": {
|
||||
"translation": "",
|
||||
"defaultMessage": "New email",
|
||||
"description": "Prompt for entering a new email",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"new_phone_number": {
|
||||
"translation": "",
|
||||
"defaultMessage": "New phone number",
|
||||
"description": "Prompt for entering a new telephone number",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"change_email": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Change email",
|
||||
"description": "Prompt to change current email",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"change_phonel": {
|
||||
"translation": "",
|
||||
"defaultMessage": "Change phone number",
|
||||
"description": "Prompt to change current phone number",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
// This is a generated file. Don't edit.
|
||||
|
||||
export const PACKAGE_VERSION = "0.21.0-rc2";
|
||||
export const PACKAGE_VERSION = "0.21.0";
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
// Edit account parameters.
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { parsePhoneNumber } from 'libphonenumber-js/mobile';
|
||||
|
||||
import AvatarUpload from '../widgets/avatar-upload.jsx';
|
||||
import BadgeList from '../widgets/badge-list.jsx';
|
||||
|
||||
import { makeImageUrl } from '../lib/blob-helpers.js';
|
||||
import { MAX_TITLE_LENGTH, MAX_TOPIC_DESCRIPTION_LENGTH } from '../config.js';
|
||||
import CredentialEdit from '../widgets/credential-edit.jsx';
|
||||
|
||||
function _clip(str, length) {
|
||||
return str && str.substring(0, length);
|
||||
@@ -20,15 +22,76 @@ export default class AccountSettingsView extends React.Component {
|
||||
this.state = {
|
||||
fullName: _clip(me.public ? me.public.fn : undefined, MAX_TITLE_LENGTH),
|
||||
description: _clip(me.public ? me.public.note : undefined, MAX_TOPIC_DESCRIPTION_LENGTH),
|
||||
avatar: makeImageUrl(me.public ? me.public.photo : null)
|
||||
avatar: makeImageUrl(me.public ? me.public.photo : null),
|
||||
credentials: me.getCredentials() || [],
|
||||
credEdit: undefined
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const me = this.props.tinode.getMeTopic();
|
||||
me.onCredsUpdated = _ => this.setState({credentials: me.getCredentials()});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
const me = this.props.tinode.getMeTopic();
|
||||
me.onCredsUpdated = null;
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.credEdit) {
|
||||
return (
|
||||
<CredentialEdit
|
||||
method={this.state.credEdit.meth}
|
||||
val={this.state.credEdit.val}
|
||||
done={this.state.credEdit.done}
|
||||
onShowCountrySelector={this.props.onShowCountrySelector}
|
||||
onSubmit={this.props.onCredAdd}
|
||||
onCancel={_ => this.setState({credEdit: undefined})}
|
||||
onError={this.props.onError} />
|
||||
);
|
||||
}
|
||||
|
||||
const credentials = [];
|
||||
this.state.credentials.forEach((cred, idx) => {
|
||||
if (!['email', 'tel'].includes(cred.meth)) {
|
||||
// Skip unknown methods.
|
||||
return ;
|
||||
}
|
||||
|
||||
let val = cred.val
|
||||
if (cred.meth == 'tel') {
|
||||
const number = parsePhoneNumber(cred.val);
|
||||
val = number ? number.formatInternational() : cred.val;
|
||||
}
|
||||
|
||||
credentials.push(
|
||||
<div className="group quoted" key={idx}>
|
||||
<tt className="clickable" onClick={e => {e.preventDefault(); this.setState({credEdit: cred});}}>{val}</tt>
|
||||
<span> {
|
||||
cred.done ? null :
|
||||
<>
|
||||
<i className="material-icons">pending</i>
|
||||
<a href="#" onClick={e => {e.preventDefault(); this.props.onCredDelete(cred.meth, cred.val);}}>
|
||||
<i className="material-icons">delete</i>
|
||||
</a>
|
||||
</>
|
||||
}</span>
|
||||
</div>);
|
||||
});
|
||||
if (credentials.length > 0) {
|
||||
// Add title as the first element.
|
||||
credentials.unshift(
|
||||
<label className="small" key={'title'}>
|
||||
<FormattedMessage id="label_user_contacts" defaultMessage="Contacts"
|
||||
description="Label for user contacts" />
|
||||
</label>);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="scrollable-panel">
|
||||
<div className="panel-form-column">
|
||||
<a href="#" className="flat-button float-right" onClick={(e) => {e.preventDefault(); this.props.onNavigate('general');}}>
|
||||
<a href="#" className="flat-button float-right" onClick={e => {e.preventDefault(); this.props.onNavigate('general');}}>
|
||||
<i className="material-icons">edit</i>
|
||||
<FormattedMessage id="button_edit" defaultMessage="Edit" description="Call to action [Edit]" />
|
||||
</a>
|
||||
@@ -61,20 +124,24 @@ export default class AccountSettingsView extends React.Component {
|
||||
<FormattedMessage id="label_description" defaultMessage="Description"
|
||||
description="Label for editing topic description" />
|
||||
</label>
|
||||
<div>{this.state.description}</div>
|
||||
<div className="quoted">{this.state.description}</div>
|
||||
</div> : null}
|
||||
</div>
|
||||
<div className="hr" />
|
||||
<div className="panel-form-column">
|
||||
<a href="#" className="flat-button" onClick={(e) => {e.preventDefault(); this.props.onNavigate('notif');}}>
|
||||
<div className="group">{credentials}</div>
|
||||
</div>
|
||||
<div className="hr" />
|
||||
<div className="panel-form-column">
|
||||
<a href="#" className="flat-button" onClick={e => {e.preventDefault(); this.props.onNavigate('notif');}}>
|
||||
<i className="material-icons">notifications</i> <FormattedMessage id="sidepanel_title_acc_notifications"
|
||||
defaultMessage="Notifications" description="Sidepanel title for AccNotificationsView." />
|
||||
</a>
|
||||
<a href="#" className="flat-button" onClick={(e) => {e.preventDefault(); this.props.onNavigate('security');}}>
|
||||
<a href="#" className="flat-button" onClick={e => {e.preventDefault(); this.props.onNavigate('security');}}>
|
||||
<i className="material-icons">security</i> <FormattedMessage id="button_security"
|
||||
defaultMessage="Security" description="Navigaton button for security panel." />
|
||||
</a>
|
||||
<a href="#" className="flat-button" onClick={(e) => {e.preventDefault(); this.props.onNavigate('support');}}>
|
||||
<a href="#" className="flat-button" onClick={e => {e.preventDefault(); this.props.onNavigate('support');}}>
|
||||
<i className="material-icons">contact_support</i> <FormattedMessage id="sidepanel_title_acc_support"
|
||||
defaultMessage="Support" description="Sidepanel title for AccSupportView." />
|
||||
</a>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { FormattedMessage } from 'react-intl';
|
||||
import AvatarCrop from '../widgets/avatar-crop.jsx';
|
||||
import AvatarUpload from '../widgets/avatar-upload.jsx';
|
||||
import CheckBox from '../widgets/checkbox.jsx';
|
||||
const PhoneEdit = React.lazy(_ => import('../widgets/phone-edit.jsx'));
|
||||
import PhoneEdit from '../widgets/phone-edit.jsx';
|
||||
import VisiblePassword from '../widgets/visible-password.jsx';
|
||||
|
||||
import LocalStorageUtil from '../lib/local-storage.js';
|
||||
@@ -30,7 +30,6 @@ export default class CreateAccountView extends React.PureComponent {
|
||||
uploadUrl: null,
|
||||
newAvatar: null,
|
||||
newAvatarMime: null,
|
||||
errorCleared: false,
|
||||
buttonDisabled: false,
|
||||
saveToken: LocalStorageUtil.getObject('keep-logged-in')
|
||||
};
|
||||
@@ -85,7 +84,6 @@ export default class CreateAccountView extends React.PureComponent {
|
||||
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
this.setState({errorCleared: false});
|
||||
this.props.onCreateAccount(
|
||||
this.state.login.trim(),
|
||||
this.state.password.trim(),
|
||||
@@ -144,9 +142,6 @@ export default class CreateAccountView extends React.PureComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
// "reqCred":{"auth":["email"]}
|
||||
const method = (this.props.tinode.getServerParam('reqCred', {}).auth || [])[0] || 'email';
|
||||
|
||||
if (this.state.newAvatar) {
|
||||
return (
|
||||
<AvatarCrop
|
||||
@@ -192,7 +187,7 @@ export default class CreateAccountView extends React.PureComponent {
|
||||
value={this.state.fn} onChange={this.handleFnChange} required/>
|
||||
}</FormattedMessage>
|
||||
</div>
|
||||
{method == 'email' ?
|
||||
{this.props.reqCredMethod == 'email' ?
|
||||
<div className="panel-form-row">
|
||||
<FormattedMessage id="email_prompt" defaultMessage="Email, e.g. jdoe@example.com"
|
||||
description="Input placeholder for email entry">{
|
||||
@@ -200,19 +195,16 @@ export default class CreateAccountView extends React.PureComponent {
|
||||
value={this.state.email} onChange={this.handleEmailChange} required/>
|
||||
}</FormattedMessage>
|
||||
</div>
|
||||
: method == 'tel' ?
|
||||
: this.props.reqCredMethod == 'tel' ?
|
||||
<><div className="panel-form-row">
|
||||
<label className="small gray"><FormattedMessage id="mobile_phone_number" defaultMessage="Mobile phone number"
|
||||
description="Prompt for entering a mobile phone number" /></label>
|
||||
</div>
|
||||
<div className="panel-form-row">
|
||||
<Suspense fallback={<div><FormattedMessage id="loading_note" defaultMessage="Loading..."
|
||||
description="Message shown when component is loading"/></div>}>
|
||||
<PhoneEdit
|
||||
autoFocus={false}
|
||||
onShowCountrySelector={this.props.onShowCountrySelector}
|
||||
onSubmit={this.handlePhoneChange} />
|
||||
</Suspense>
|
||||
</div></>
|
||||
: null
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import ErrorPanel from '../widgets/error-panel.jsx';
|
||||
import GroupManager from '../widgets/group-manager.jsx';
|
||||
import MenuCancel from '../widgets/menu-cancel.jsx';
|
||||
import PermissionsEditor from '../widgets/permissions-editor.jsx';
|
||||
import TopicCommon from '../widgets/topic-common.jsx';
|
||||
import TopicCommonView from './topic-common-view.jsx';
|
||||
import TopicSecurity from '../widgets/topic-security.jsx';
|
||||
|
||||
import { MAX_TITLE_LENGTH, MAX_TOPIC_DESCRIPTION_LENGTH, NO_ACCESS_MODE } from '../config.js';
|
||||
@@ -476,9 +476,10 @@ class InfoView extends React.Component {
|
||||
onCancel={this.handleBackNavigate} />
|
||||
:
|
||||
view == 'general' ?
|
||||
<TopicCommon
|
||||
<TopicCommonView
|
||||
tinode={this.props.tinode}
|
||||
topic={this.props.topic}
|
||||
reqCredMethod={this.props.reqCredMethod}
|
||||
onCredAdd={this.props.onCredAdd}
|
||||
onUpdateTagsRequest={this.props.onTopicTagsUpdateRequest}
|
||||
onCredConfirm={this.props.onCredConfirm}
|
||||
|
||||
@@ -672,6 +672,9 @@ class MessagesView extends React.Component {
|
||||
|
||||
// The 'msg' could be false-ish if some message ranges were deleted.
|
||||
handleMessageUpdate(msg) {
|
||||
if (!this.state.topic) {
|
||||
return;
|
||||
}
|
||||
const topic = this.props.tinode.getTopic(this.state.topic);
|
||||
if (!msg) {
|
||||
// msg could be null if one or more messages were deleted.
|
||||
|
||||
@@ -1,13 +1,26 @@
|
||||
// A password reset form.
|
||||
import React, { Suspense } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import React from 'react';
|
||||
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
|
||||
|
||||
const PhoneEdit = React.lazy(_ => import('../widgets/phone-edit.jsx'));
|
||||
import PhoneEdit from '../widgets/phone-edit.jsx';
|
||||
import VisiblePassword from '../widgets/visible-password.jsx';
|
||||
|
||||
import HashNavigation from '../lib/navigation.js';
|
||||
|
||||
export default class PasswordResetView extends React.PureComponent {
|
||||
const messages = defineMessages({
|
||||
password_reset_email_sent: {
|
||||
id: 'password_reset_email_sent',
|
||||
defaultMessage: 'An email with security code has been sent.',
|
||||
description: 'Notification that the email with password reset instructions has been sent'
|
||||
},
|
||||
password_reset_sms_sent: {
|
||||
id: 'password_reset_sms_sent',
|
||||
defaultMessage: 'A text message with security code has been sent.',
|
||||
description: 'Notification that the SMS with password reset instructions has been sent'
|
||||
}
|
||||
});
|
||||
|
||||
class PasswordResetView extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -46,19 +59,28 @@ export default class PasswordResetView extends React.PureComponent {
|
||||
scheme: 'token',
|
||||
token: this.state.token
|
||||
});
|
||||
} else if (this.state.code && this.method) {
|
||||
} else if (this.state.code && this.props.reqCredMethod) {
|
||||
// Reset using security code.
|
||||
// The secret is structured as <code>:<cred_method>:<cred_value>, "123456:email:alice@example.com".
|
||||
const cred = this.state.email.trim() || this.state.tel.trim();
|
||||
this.props.onReset(this.state.password.trim(), {
|
||||
scheme: 'code',
|
||||
secret: `${this.state.code}:${this.method}:${cred}`
|
||||
secret: btoa(`${this.state.code}:${this.props.reqCredMethod}:${cred}`)
|
||||
});
|
||||
} else {
|
||||
// Send email or SMS with the secret code.
|
||||
const email = this.state.email.trim();
|
||||
const tel = this.state.tel.trim();
|
||||
this.setState({email: email, tel: tel});
|
||||
this.props.onRequest(this.method, email || tel).then(_ => this.setState({sent: true}));
|
||||
this.props.onRequest(this.props.reqCredMethod, email || tel)
|
||||
.then(_ => {
|
||||
this.setState({sent: true});
|
||||
const msg = this.props.reqCredMethod == 'email' ? messages.password_reset_email_sent :
|
||||
this.props.reqCredMethod == 'tel' ? messages.password_reset_sms_sent : null;
|
||||
if (msg) {
|
||||
this.props.onError(this.props.intl.formatMessage(msg), 'info');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,9 +102,6 @@ export default class PasswordResetView extends React.PureComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
// "reqCred":{"auth":["email"]}
|
||||
this.method = (this.props.tinode.getServerParam('reqCred', {}).auth || [])[0] || 'email';
|
||||
|
||||
const showCredentialInput = !(this.state.token && this.state.scheme);
|
||||
const showPasswordInput = !showCredentialInput || this.state.haveCode || this.state.sent;
|
||||
|
||||
@@ -140,31 +159,13 @@ export default class PasswordResetView extends React.PureComponent {
|
||||
</label>
|
||||
</div>
|
||||
<div className="panel-form-row">
|
||||
<Suspense fallback={<div className="panel-form-row"><FormattedMessage id="loading_note"
|
||||
defaultMessage="Loading..." description="Message shown when component is loading"/></div>}>
|
||||
<PhoneEdit
|
||||
autoFocus={true}
|
||||
onShowCountrySelector={this.props.onShowCountrySelector}
|
||||
onSubmit={number => this.setState({tel: number})} />
|
||||
</Suspense>
|
||||
</div>
|
||||
</>);
|
||||
|
||||
const sentNotification = (<>{
|
||||
this.method == 'email' ?
|
||||
<FormattedMessage id="password_reset_email_sent"
|
||||
defaultMessage="An email with security code has been sent to {email}. Enter the code below."
|
||||
values={{email: <tt>{this.state.email}</tt>}}
|
||||
description="Notification that the email with password reset instructions has been sent" />
|
||||
: this.method == 'tel' ?
|
||||
<FormattedMessage id="password_reset_sms_sent"
|
||||
defaultMessage="A text message with security code has been sent to {phone}. Enter the code below."
|
||||
values={{phone: <tt>{this.state.tel}</tt>}}
|
||||
description="Notification that the SMS with password reset instructions has been sent" />
|
||||
:
|
||||
null
|
||||
}</>);
|
||||
|
||||
const codeInput = (<>
|
||||
<div>
|
||||
<label className="small gray" htmlFor="enter-confirmation-code">
|
||||
@@ -183,11 +184,12 @@ export default class PasswordResetView extends React.PureComponent {
|
||||
</div>
|
||||
</>);
|
||||
|
||||
const credentialInput = this.method == 'email' ? emailInput : this.method == 'tel' ? phoneInput : null;
|
||||
const credentialInput = this.props.reqCredMethod == 'email' ?
|
||||
emailInput : this.props.reqCredMethod == 'tel' ? phoneInput : null;
|
||||
|
||||
return (
|
||||
<form id="password-reset-form" onSubmit={this.handleSubmit}>
|
||||
{this.state.sent ? sentNotification : showCredentialInput ? credentialInput : null}
|
||||
{!this.state.sent && showCredentialInput ? credentialInput : null}
|
||||
{this.state.haveCode || this.state.sent ? codeInput : null}
|
||||
{showPasswordInput ? passwordInput : null}
|
||||
<div className="dialog-buttons">
|
||||
@@ -209,3 +211,5 @@ export default class PasswordResetView extends React.PureComponent {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default injectIntl(PasswordResetView);
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import React from 'react';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import React, { Suspense } from 'react';
|
||||
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
|
||||
|
||||
import ErrorPanel from '../widgets/error-panel.jsx';
|
||||
import LoadSpinner from '../widgets/load-spinner.jsx';
|
||||
import SideNavbar from '../widgets/side-navbar.jsx';
|
||||
import TopicCommon from '../widgets/topic-common.jsx';
|
||||
import TopicCommonView from './topic-common-view.jsx';
|
||||
|
||||
import AccountSettingsView from './account-settings-view.jsx';
|
||||
const AccountSettingsView = React.lazy(_ => import('./account-settings-view.jsx'));
|
||||
import ContactsView from './contacts-view.jsx';
|
||||
import CreateAccountView from './create-account-view.jsx';
|
||||
const CreateAccountView = React.lazy(_ => import('./create-account-view.jsx'));
|
||||
import AccNotificationsView from './acc-notifications-view.jsx';
|
||||
import AccSecurityView from './acc-security-view.jsx';
|
||||
import AccSupportView from './acc-support-view.jsx';
|
||||
import LoginView from './login-view.jsx';
|
||||
import NewTopicView from './new-topic-view.jsx';
|
||||
import PasswordResetView from './password-reset-view.jsx';
|
||||
const PasswordResetView = React.lazy(_ => import('./password-reset-view.jsx'));
|
||||
import SettingsView from './settings-view.jsx';
|
||||
import ValidationView from './validation-view.jsx';
|
||||
|
||||
@@ -155,13 +155,16 @@ class SidepanelView extends React.PureComponent {
|
||||
onPersistenceChange={this.props.onPersistenceChange} /> :
|
||||
|
||||
view === 'register' ?
|
||||
<Suspense fallback={<div className="panel-form-row"><FormattedMessage id="loading_note"
|
||||
defaultMessage="Loading..." description="Message shown when component is loading"/></div>}>
|
||||
<CreateAccountView
|
||||
tinode={this.props.tinode}
|
||||
serverVersion={this.props.serverVersion}
|
||||
reqCredMethod={this.props.reqCredMethod}
|
||||
onShowCountrySelector={this.props.onShowCountrySelector}
|
||||
onCreateAccount={this.props.onCreateAccount}
|
||||
onCancel={this.props.onCancel}
|
||||
onError={this.props.onError} /> :
|
||||
onError={this.props.onError} />
|
||||
</Suspense> :
|
||||
|
||||
view === 'settings' ?
|
||||
<SettingsView
|
||||
@@ -172,22 +175,28 @@ class SidepanelView extends React.PureComponent {
|
||||
onUpdate={this.props.onGlobalSettings} /> :
|
||||
|
||||
view === 'edit' ?
|
||||
<Suspense fallback={<div className="panel-form-row"><FormattedMessage id="loading_note"
|
||||
defaultMessage="Loading..." description="Message shown when component is loading"/></div>}>
|
||||
<AccountSettingsView
|
||||
tinode={this.props.tinode}
|
||||
myUserId={this.props.myUserId}
|
||||
trustedBadges={this.props.trustedBadges}
|
||||
onNavigate={this.props.onNavigate} /> :
|
||||
|
||||
(view === 'general' || view === 'crop') ?
|
||||
<TopicCommon
|
||||
topic="me"
|
||||
tinode={this.props.tinode}
|
||||
myUserId={this.props.myUserId}
|
||||
onUpdateTopicDesc={this.props.onUpdateAccountDesc}
|
||||
onUpdateTagsRequest={this.props.onUpdateAccountTags}
|
||||
onShowCountrySelector={this.props.onShowCountrySelector}
|
||||
onNavigate={this.props.onNavigate}
|
||||
onCredAdd={this.props.onCredAdd}
|
||||
onCredDelete={this.props.onCredDelete}
|
||||
onCredConfirm={this.props.onCredConfirm}
|
||||
onError={this.props.onError} />
|
||||
</Suspense> :
|
||||
|
||||
(view === 'general' || view === 'crop') ?
|
||||
<TopicCommonView
|
||||
topic="me"
|
||||
tinode={this.props.tinode}
|
||||
myUserId={this.props.myUserId}
|
||||
reqCredMethod={this.props.reqCredMethod}
|
||||
onUpdateTopicDesc={this.props.onUpdateAccountDesc}
|
||||
onUpdateTagsRequest={this.props.onUpdateAccountTags}
|
||||
onError={this.props.onError} /> :
|
||||
|
||||
view === 'notif' ?
|
||||
@@ -246,13 +255,17 @@ class SidepanelView extends React.PureComponent {
|
||||
onCancel={this.props.onCancel} /> :
|
||||
|
||||
view === 'reset' ?
|
||||
<Suspense fallback={<div className="panel-form-row"><FormattedMessage id="loading_note"
|
||||
defaultMessage="Loading..." description="Message shown when component is loading"/></div>}>
|
||||
<PasswordResetView
|
||||
tinode={this.props.tinode}
|
||||
serverVersion={this.props.serverVersion}
|
||||
reqCredMethod={this.props.reqCredMethod}
|
||||
onShowCountrySelector={this.props.onShowCountrySelector}
|
||||
onRequest={this.props.onPasswordResetRequest}
|
||||
onReset={this.props.onResetPassword}
|
||||
onCancel={this.props.onCancel} /> :
|
||||
onCancel={this.props.onCancel}
|
||||
onError={this.props.onError} />
|
||||
</Suspense> :
|
||||
null}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -266,6 +266,7 @@ class TinodeWeb extends React.Component {
|
||||
// Merged results of a search query and p2p chats.
|
||||
searchableContacts: [],
|
||||
// Credential validation.
|
||||
reqCredMethod: undefined,
|
||||
credMethod: undefined,
|
||||
credCode: undefined,
|
||||
credToken: undefined,
|
||||
@@ -615,7 +616,9 @@ class TinodeWeb extends React.Component {
|
||||
|
||||
const params = this.tinode.getServerInfo();
|
||||
this.setState({
|
||||
serverVersion: params.ver + ' ' + (params.build ? params.build : 'none')
|
||||
serverVersion: params.ver + ' ' + (params.build ? params.build : 'none'),
|
||||
// "reqCred":{"auth":["email"]}
|
||||
reqCredMethod: ((params.reqCred || {}).auth || [])[0] || 'email'
|
||||
});
|
||||
|
||||
if (this.state.autoLogin) {
|
||||
@@ -2012,6 +2015,7 @@ class TinodeWeb extends React.Component {
|
||||
serverAddress={this.state.serverAddress}
|
||||
secureConnection={this.state.secureConnection}
|
||||
serverVersion={this.state.serverVersion}
|
||||
reqCredMethod={this.state.reqCredMethod}
|
||||
|
||||
onGlobalSettings={this.handleGlobalSettings}
|
||||
onSignUp={this.handleNewAccount}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
// View for editing topic parameters (including 'me' topic).
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import TopicDescEdit from '../widgets/topic-desc-edit.jsx';
|
||||
|
||||
import { arrayEqual } from '../lib/utils.js';
|
||||
|
||||
export default class TopicCommonView extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
const topic = this.props.tinode.getTopic(this.props.topic);
|
||||
const acs = topic.getAccessMode();
|
||||
this.state = {
|
||||
tags: []
|
||||
};
|
||||
|
||||
this.previousTagsUpdated = undefined;
|
||||
|
||||
this.onTagsUpdated = this.onTagsUpdated.bind(this);
|
||||
this.handleTagsUpdated = this.handleTagsUpdated.bind(this);
|
||||
}
|
||||
|
||||
// No need to separately handle component mount.
|
||||
componentDidUpdate(props) {
|
||||
const topic = this.props.tinode.getTopic(props.topic);
|
||||
if (!topic) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (topic.onTagsUpdated != this.onTagsUpdated) {
|
||||
if (topic.getType() == 'grp') {
|
||||
this.previousTagsUpdated = topic.onTagsUpdated;
|
||||
topic.onTagsUpdated = this.onTagsUpdated;
|
||||
} else {
|
||||
this.previousTagsUpdated = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.state.topic != props.topic) {
|
||||
this.setState({topic: props.topic});
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
const topic = this.props.tinode.getTopic(this.props.topic);
|
||||
topic.onTagsUpdated = this.previousTagsUpdated;
|
||||
}
|
||||
|
||||
// Server informs that the tags have been updated.
|
||||
onTagsUpdated(tags) {
|
||||
this.setState({tags: tags});
|
||||
|
||||
if (this.previousTagsUpdated && this.previousTagsUpdated != this.onTagsUpdated) {
|
||||
this.previousTagsUpdated(tags);
|
||||
}
|
||||
}
|
||||
|
||||
// Request server to change tags.
|
||||
handleTagsUpdated(tags) {
|
||||
if (!arrayEqual(this.state.tags.slice(0), tags.slice(0))) {
|
||||
this.props.onUpdateTagsRequest(this.props.topic, tags);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="scrollable-panel">
|
||||
<TopicDescEdit
|
||||
tinode={this.props.tinode}
|
||||
topic={this.props.topic}
|
||||
onUpdateTopicDesc={this.props.onUpdateTopicDesc}
|
||||
onUpdateTags={this.handleTagsUpdated}
|
||||
onError={this.props.onError} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -24,7 +24,7 @@ class ValidationView extends React.PureComponent {
|
||||
codeReceived: props.credCode
|
||||
};
|
||||
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
this.handleCodeChange = this.handleCodeChange.bind(this);
|
||||
this.handleKeyPress = this.handleKeyPress.bind(this);
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
this.handleCancel = this.handleCancel.bind(this);
|
||||
@@ -56,8 +56,8 @@ class ValidationView extends React.PureComponent {
|
||||
}
|
||||
|
||||
|
||||
handleChange(e) {
|
||||
this.setState({code: e.target.value.trim()});
|
||||
handleCodeChange(e) {
|
||||
this.setState({code: e.target.value.replace(/[^\d]/g, '')});
|
||||
}
|
||||
|
||||
handleKeyPress(e) {
|
||||
@@ -99,7 +99,7 @@ class ValidationView extends React.PureComponent {
|
||||
defaultMessage="Numbers only" description="Prompt for numeric conformation code">{
|
||||
(numbers_only) => <input type="text" id="enter-confirmation-code"
|
||||
placeholder={numbers_only}
|
||||
value={this.state.code} onChange={this.handleChange}
|
||||
value={this.state.code} onChange={this.handleCodeChange}
|
||||
onKeyPress={this.handleKeyPress} required />
|
||||
}</FormattedMessage>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
// Enter one credential at a time.
|
||||
|
||||
import React from 'react';
|
||||
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
|
||||
import PhoneEdit from './phone-edit.jsx';
|
||||
import { parsePhoneNumber } from 'libphonenumber-js/mobile';
|
||||
|
||||
const messages = defineMessages({
|
||||
password_reset_email_sent: {
|
||||
id: 'password_reset_email_sent',
|
||||
defaultMessage: 'An email with security code has been sent.',
|
||||
description: 'Notification that the email with password reset instructions has been sent'
|
||||
},
|
||||
password_reset_sms_sent: {
|
||||
id: 'password_reset_sms_sent',
|
||||
defaultMessage: 'A text message with security code has been sent.',
|
||||
description: 'Notification that the SMS with password reset instructions has been sent'
|
||||
},
|
||||
});
|
||||
|
||||
class CredentialEdit extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
code: '',
|
||||
tel: '',
|
||||
email: '',
|
||||
sent: false
|
||||
};
|
||||
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
this.handleEmailChange = this.handleEmailChange.bind(this);
|
||||
this.handlePhoneChange = this.handlePhoneChange.bind(this);
|
||||
this.handleCodeChange = this.handleCodeChange.bind(this);
|
||||
}
|
||||
|
||||
static formatPhoneNumber(raw) {
|
||||
let number;
|
||||
try {
|
||||
number = parsePhoneNumber(raw);
|
||||
} catch (err) {}
|
||||
return number ? number.formatInternational() : raw;
|
||||
}
|
||||
|
||||
handleEmailChange(e) {
|
||||
this.setState({email: e.target.value});
|
||||
}
|
||||
|
||||
handlePhoneChange(number) {
|
||||
this.setState({tel: number});
|
||||
}
|
||||
|
||||
handleCodeChange(e) {
|
||||
this.setState({code: e.target.value.replace(/[^\d]/g, '')});
|
||||
}
|
||||
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
const value = this.props.method == 'email' ? this.state.email : this.state.tel;
|
||||
if (value) {
|
||||
this.props.onSubmit(this.props.method, value);
|
||||
this.setState({sent: true});
|
||||
const msg = this.props.method == 'email' ? messages.password_reset_email_sent : messages.password_reset_sms_sent;
|
||||
this.props.onError(this.props.intl.formatMessage(msg), 'info');
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const readyForCode = this.state.sent || !this.props.done;
|
||||
const currentValue = CredentialEdit.formatPhoneNumber(readyForCode ?
|
||||
(this.state.tel || this.state.email) : this.props.val);
|
||||
|
||||
const changeEmail = (
|
||||
<><div className="panel-form-row">
|
||||
<label className="large"><FormattedMessage id="change_email" defaultMessage="Change email"
|
||||
description="Prompt to change current email" /></label>
|
||||
</div>
|
||||
<div className="group">
|
||||
<label className="small gray">
|
||||
<FormattedMessage id="current_email" defaultMessage="Current email" description="Label for old email" />
|
||||
</label>
|
||||
</div></>);
|
||||
|
||||
const changePhone = (
|
||||
<><div className="panel-form-row">
|
||||
<label className="large"><FormattedMessage id="change_phonel" defaultMessage="Change phone number"
|
||||
description="Prompt to change current phone number"/></label>
|
||||
</div>
|
||||
<div className="group">
|
||||
<label className="small gray">
|
||||
<FormattedMessage id="current_phone" defaultMessage="Current phone number" description="Label for old phone" />
|
||||
</label>
|
||||
</div></>
|
||||
);
|
||||
|
||||
const newEmailLabel = (<label className="small gray">
|
||||
<FormattedMessage id="new_email" defaultMessage="New email"
|
||||
description="Prompt for entering a new email" />
|
||||
</label>);
|
||||
|
||||
const newEmailInput = (
|
||||
<><div className="group">{newEmailLabel}</div>
|
||||
<div className="group">
|
||||
<FormattedMessage id="email_prompt" defaultMessage="Email, e.g. jdoe@example.com"
|
||||
description="Input placeholder for email entry">{
|
||||
(email_prompt) => <input type="email" placeholder={email_prompt} autoComplete="email"
|
||||
value={this.state.email} onChange={this.handleEmailChange} required/>
|
||||
}</FormattedMessage>
|
||||
</div></>
|
||||
);
|
||||
|
||||
const newPhoneLabel = (<label className="small gray">
|
||||
<FormattedMessage id="new_phone_number" defaultMessage="New phone number"
|
||||
description="Prompt for entering a new telephone number" />
|
||||
</label>);
|
||||
|
||||
const newPhoneInput = (
|
||||
<><div className="group">{newPhoneLabel}</div>
|
||||
<div className="panel-form-row">
|
||||
<PhoneEdit
|
||||
autoFocus={true}
|
||||
onShowCountrySelector={this.props.onShowCountrySelector}
|
||||
onSubmit={this.handlePhoneChange} />
|
||||
</div></>
|
||||
);
|
||||
|
||||
const codeInput = (
|
||||
<><div className="group">
|
||||
<label className="small gray"><FormattedMessage id="enter_confirmation_code_prompt" defaultMessage="Confirmation code"
|
||||
description="Request to enter confirmation code" /></label>
|
||||
</div>
|
||||
<div className="group">
|
||||
<FormattedMessage id="numeric_confirmation_code_prompt" defaultMessage="Numbers only"
|
||||
description="Prompt for numeric conformation code">{
|
||||
(numbers_only) => <input type="text" placeholder={numbers_only} maxLength={10}
|
||||
value={this.state.code} onChange={this.handleCodeChange} required/>
|
||||
}</FormattedMessage>
|
||||
</div></>
|
||||
);
|
||||
|
||||
return (<form className="panel-form-column" onSubmit={this.handleSubmit}>
|
||||
{readyForCode ? null :
|
||||
this.props.method == 'email' ?
|
||||
changeEmail
|
||||
: this.props.method == 'tel' ?
|
||||
changePhone
|
||||
: null}
|
||||
<div className="panel-form-row">
|
||||
<tt className="quoted">{currentValue}</tt>
|
||||
</div>
|
||||
{readyForCode ? null :
|
||||
this.props.method == 'email' ?
|
||||
newEmailInput
|
||||
: this.props.method == 'tel' ?
|
||||
newPhoneInput
|
||||
: null}
|
||||
{readyForCode ? codeInput : null}
|
||||
<div className="dialog-buttons">
|
||||
<button className="secondary" onClick={this.props.onCancel}>
|
||||
<FormattedMessage id="button_cancel" defaultMessage="Cancel" description="Button [Cancel]" />
|
||||
</button>
|
||||
<button className="primary" type="submit" >
|
||||
<FormattedMessage id="button_ok" defaultMessage="OK" description="Button [OK]" />
|
||||
</button>
|
||||
</div>
|
||||
</form>);
|
||||
}
|
||||
}
|
||||
|
||||
export default injectIntl(CredentialEdit);
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import React from 'react';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { getExampleNumber, parsePhoneNumber } from 'libphonenumber-js/mobile';
|
||||
import { AsYouType, getExampleNumber, parsePhoneNumber } from 'libphonenumber-js/mobile';
|
||||
import examples from 'libphonenumber-js/mobile/examples'
|
||||
|
||||
import * as dcodes from '../dcodes.json';
|
||||
@@ -40,7 +40,10 @@ class PhoneEdit extends React.PureComponent {
|
||||
}
|
||||
|
||||
handleChange(e) {
|
||||
this.setState({localNumber: this.filterNumber(e.target.value)});
|
||||
const prefix = `+${this.state.dialCode}`;
|
||||
let formatted = new AsYouType().input(`${prefix}${this.filterNumber(e.target.value)}`);
|
||||
formatted = formatted.substring(prefix.length).trim();
|
||||
this.setState({localNumber: formatted});
|
||||
}
|
||||
|
||||
handleFinished(e) {
|
||||
@@ -55,6 +58,8 @@ class PhoneEdit extends React.PureComponent {
|
||||
this.inputField.setCustomValidity(this.props.intl.formatMessage(messages.mobile_number_required));
|
||||
return;
|
||||
}
|
||||
|
||||
this.inputField.setCustomValidity('');
|
||||
this.props.onSubmit(number.format('E.164'));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,182 +0,0 @@
|
||||
// View for editing topic (including 'me' topic) parameters.
|
||||
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import TopicDescEdit from '../widgets/topic-desc-edit.jsx';
|
||||
|
||||
import { arrayEqual, asEmail, asPhone } from '../lib/utils.js';
|
||||
|
||||
export default class TopicCommon extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
const topic = this.props.tinode.getTopic(this.props.topic);
|
||||
const acs = topic.getAccessMode();
|
||||
this.state = {
|
||||
isMe: this.props.topic == 'me',
|
||||
owner: acs && acs.isOwner(),
|
||||
credentials: (topic.getCredentials ? topic.getCredentials() : null) || [],
|
||||
addCredActive: false,
|
||||
addCredInvalid: false,
|
||||
newCred: '',
|
||||
tags: []
|
||||
};
|
||||
|
||||
this.previousTagsUpdated = undefined;
|
||||
|
||||
this.onTagsUpdated = this.onTagsUpdated.bind(this);
|
||||
this.handleTagsUpdated = this.handleTagsUpdated.bind(this);
|
||||
this.tnCredsUpdated = this.tnCredsUpdated.bind(this);
|
||||
this.handleCredChange = this.handleCredChange.bind(this);
|
||||
this.handleCredKeyDown = this.handleCredKeyDown.bind(this);
|
||||
this.handleCredEntered = this.handleCredEntered.bind(this);
|
||||
}
|
||||
|
||||
// No need to separately handle component mount.
|
||||
componentDidUpdate(props) {
|
||||
const topic = this.props.tinode.getTopic(props.topic);
|
||||
if (!topic) {
|
||||
return;
|
||||
}
|
||||
|
||||
topic.onCredsUpdated = this.tnCredsUpdated;
|
||||
|
||||
if (topic.onTagsUpdated != this.onTagsUpdated) {
|
||||
if (topic.getType() == 'grp') {
|
||||
this.previousTagsUpdated = topic.onTagsUpdated;
|
||||
topic.onTagsUpdated = this.onTagsUpdated;
|
||||
} else {
|
||||
this.previousTagsUpdated = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.state.topic != props.topic) {
|
||||
this.setState({topic: props.topic});
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
const topic = this.props.tinode.getTopic(this.props.topic);
|
||||
topic.onCredsUpdated = undefined;
|
||||
topic.onTagsUpdated = this.previousTagsUpdated;
|
||||
}
|
||||
|
||||
tnCredsUpdated(creds) {
|
||||
this.setState({credentials: creds || []});
|
||||
}
|
||||
|
||||
handleCredChange(e) {
|
||||
this.setState({newCred: e.target.value, addCredInvalid: false});
|
||||
}
|
||||
|
||||
handleCredKeyDown(e) {
|
||||
if (e.keyCode === 27) {
|
||||
// Escape pressed
|
||||
this.setState({newCred: '', addCredActive: false});
|
||||
} else if (e.keyCode === 13) {
|
||||
// Enter pressed
|
||||
this.handleCredEntered(e);
|
||||
}
|
||||
}
|
||||
|
||||
handleCredEntered(e) {
|
||||
const value = this.state.newCred.trim();
|
||||
if (!value) {
|
||||
this.setState({addCredActive: false, addCredInvalid: false});
|
||||
return;
|
||||
}
|
||||
|
||||
let val = asPhone(value);
|
||||
let method;
|
||||
if (val) {
|
||||
method = 'tel';
|
||||
} else {
|
||||
val = asEmail(value);
|
||||
if (val) {
|
||||
method = 'email';
|
||||
}
|
||||
}
|
||||
if (method) {
|
||||
this.props.onCredAdd(method, val);
|
||||
this.setState({addCredActive: false, newCred: ''});
|
||||
} else {
|
||||
this.setState({addCredInvalid: true});
|
||||
}
|
||||
}
|
||||
|
||||
// Server informs that the tags have been updated.
|
||||
onTagsUpdated(tags) {
|
||||
this.setState({tags: tags});
|
||||
|
||||
if (this.previousTagsUpdated && this.previousTagsUpdated != this.onTagsUpdated) {
|
||||
this.previousTagsUpdated(tags);
|
||||
}
|
||||
}
|
||||
|
||||
// Request server to change tags.
|
||||
handleTagsUpdated(tags) {
|
||||
if (!arrayEqual(this.state.tags.slice(0), tags.slice(0))) {
|
||||
this.props.onUpdateTagsRequest(this.props.topic, tags);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const credentials = [];
|
||||
if (this.state.isMe) {
|
||||
this.state.credentials.map((cred) => {
|
||||
credentials.push(
|
||||
<div key={cred.meth + ":" + cred.val + ":" + cred.done}>{cred.meth}: <tt>{cred.val}</tt>
|
||||
<span> {!cred.done ?
|
||||
<a href="#" onClick={(e) => {e.preventDefault(); this.props.onCredConfirm(cred.meth, cred.val);}}>
|
||||
<FormattedMessage id="validate_credential_action" defaultMessage="confirm"
|
||||
description="Validate credentail call to action" />
|
||||
</a>
|
||||
: null} <a href="#" onClick={(e) => {e.preventDefault(); this.props.onCredDelete(cred.meth, cred.val);}}><i
|
||||
className="material-icons gray">delete_outline</i></a></span>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="scrollable-panel">
|
||||
<TopicDescEdit
|
||||
tinode={this.props.tinode}
|
||||
topic={this.props.topic}
|
||||
onUpdateTopicDesc={this.props.onUpdateTopicDesc}
|
||||
onUpdateTags={this.handleTagsUpdated}
|
||||
onError={this.props.onError} />
|
||||
{this.state.isMe ?
|
||||
<>
|
||||
<div className="hr" />
|
||||
<div className="panel-form-column">
|
||||
<label className="small">
|
||||
<FormattedMessage id="label_user_contacts" defaultMessage="Contacts:"
|
||||
description="Label for user contacts" />
|
||||
</label>
|
||||
<div className="quoted">
|
||||
{credentials}
|
||||
{this.state.addCredActive ?
|
||||
<FormattedMessage id="phone_or_email_prompt" defaultMessage="Phone number or email"
|
||||
description="Placeholer for phone or email">{(phone_or_email_prompt) =>
|
||||
<input type="text" value={this.state.value}
|
||||
className={this.state.addCredInvalid ? 'invalid' : null}
|
||||
placeholder={phone_or_email_prompt} required="required" autoFocus
|
||||
onChange={this.handleCredChange} onKeyDown={this.handleCredKeyDown} onBlur={this.handleCredEntered} />
|
||||
}</FormattedMessage>
|
||||
: null}
|
||||
<div>
|
||||
<a href="#" onClick={(e) => {e.preventDefault(); this.setState({addCredActive: true});}}>
|
||||
<i className="material-icons">add</i>
|
||||
<FormattedMessage id="button_add_another" defaultMessage="Add another" description="Call to action [+ add another]" />
|
||||
</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"251.prod.js","mappings":"skNAQA,MAAMA,UAAkBC,IAAAA,cACtBC,YAAYC,GACVC,MAAMD,GAENE,KAAKC,QAAU,CAAC,EAChBC,EAAAA,SAAuBC,IAAQH,KAAKC,QAAQE,EAAGC,MAAQD,EAAGE,IAAI,IAE9DL,KAAKM,MAAQ,CACXC,YAAaT,EAAMS,aAAe,KAClCC,SAAUR,KAAKC,QAAQH,EAAMS,aAAe,MAC5CE,YAAa,IAGfT,KAAKU,aAAeV,KAAKU,aAAaC,KAAKX,MAC3CA,KAAKY,eAAiBZ,KAAKY,eAAeD,KAAKX,MAC/CA,KAAKa,cAAgBb,KAAKa,cAAcF,KAAKX,MAC7CA,KAAKc,oBAAsBd,KAAKc,oBAAoBH,KAAKX,KAC3D,CAEAU,aAAaK,GACXf,KAAKgB,SAAS,CAACP,YAAaT,KAAKiB,aAAaF,EAAEG,OAAOC,QACzD,CAEAP,eAAeG,GAEbA,EAAEK,iBACF,MAAMC,EAAU,GAAErB,KAAKM,MAAME,WAAWR,KAAKM,MAAMG,YAAYa,SAASC,QAAQ,SAAU,IAC1FvB,KAAKF,MAAM0B,SAAU,IAAGH,IAC1B,CAGAR,cAAcE,GACE,UAAVA,EAAEU,KACJzB,KAAKY,eAAeG,EAExB,CAEAD,sBACEd,KAAKF,MAAM4B,sBAAsB1B,KAAKM,MAAMC,YAAaP,KAAKM,MAAME,SACtE,CAGAS,aAAaI,GACX,OAAKA,EAKEA,EAAOE,QAAQ,eAAgB,IAJ7BF,CAKX,CAEAM,SACE,OACE,oCACE,0BAAMC,UAAU,YAAYC,QAAS7B,KAAKc,qBACxC,0BAAMc,UAAU,iBAAgBE,EAAAA,EAAAA,IAAU9B,KAAKM,MAAMC,aAAa,KAAa,IAC7EP,KAAKM,MAAME,SAAS,KACxB,2BAAOuB,KAAK,MAAMC,YAAahC,KAAKM,MAAM0B,YACtCb,MAAOnB,KAAKM,MAAMG,YAAawB,SAAUjC,KAAKU,aAC9CwB,UAAW,GAAIC,UAAWnC,KAAKa,cAAeuB,OAAQpC,KAAKY,eAC3DyB,UAAQ,EAACC,UAAWtC,KAAKF,MAAMwC,YAGzC,EAGF,SAAeC,EAAAA,EAAAA,YAAW5C,E","sources":["webpack://tinode-webapp/./src/widgets/phone-edit.jsx"],"sourcesContent":["// Editor for a phone number.\n\nimport React from 'react';\nimport { injectIntl } from 'react-intl';\n\nimport * as dcodes from '../dcodes.json';\nimport { flagEmoji } from '../lib/strformat';\n\nclass PhoneEdit extends React.PureComponent {\n constructor(props) {\n super(props);\n\n this.codeMap = {};\n dcodes.default.forEach(dc => { this.codeMap[dc.code] = dc.dial; });\n\n this.state = {\n countryCode: props.countryCode || 'US',\n dialCode: this.codeMap[props.countryCode || 'US'],\n localNumber: ''\n };\n\n this.handleChange = this.handleChange.bind(this);\n this.handleFinished = this.handleFinished.bind(this);\n this.handleKeyDown = this.handleKeyDown.bind(this);\n this.showCountrySelector = this.showCountrySelector.bind(this);\n }\n\n handleChange(e) {\n this.setState({localNumber: this.filterNumber(e.target.value)});\n }\n\n handleFinished(e) {\n // this.setCustomValidity(\"Mobile phone number required\");\n e.preventDefault();\n const number = `${this.state.dialCode}${this.state.localNumber.trim()}`.replace(/[^\\d]/g, '')\n this.props.onSubmit(`+${number}`);\n }\n\n\n handleKeyDown(e) {\n if (e.key === 'Enter') {\n this.handleFinished(e);\n }\n }\n\n showCountrySelector() {\n this.props.onShowCountrySelector(this.state.countryCode, this.state.dialCode);\n }\n\n // Filter out characters not permitted in a phone number.\n filterNumber(number) {\n if (!number) {\n return number;\n }\n // Leave numbers, space, (, ), -, and .\n // The + is not allowed: it's handled by the country code portion.\n return number.replace(/[^-\\s().\\d]/g, '');\n }\n\n render() {\n return (\n <>\n <span className=\"dial-code\" onClick={this.showCountrySelector}>\n <span className=\"country-flag\">{flagEmoji(this.state.countryCode)} </span>\n +{this.state.dialCode} </span>\n <input type=\"tel\" placeholder={this.state.placeholder}\n value={this.state.localNumber} onChange={this.handleChange}\n maxLength={17} onKeyDown={this.handleKeyDown} onBlur={this.handleFinished}\n required autoFocus={this.props.autoFocus} />\n </>\n );\n }\n}\n\nexport default injectIntl(PhoneEdit);\n"],"names":["PhoneEdit","React","constructor","props","super","this","codeMap","dcodes","dc","code","dial","state","countryCode","dialCode","localNumber","handleChange","bind","handleFinished","handleKeyDown","showCountrySelector","e","setState","filterNumber","target","value","preventDefault","number","trim","replace","onSubmit","key","onShowCountrySelector","render","className","onClick","flagEmoji","type","placeholder","onChange","maxLength","onKeyDown","onBlur","required","autoFocus","injectIntl"],"sourceRoot":""}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+172
-1015
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,284 +0,0 @@
|
||||
/******/ (() => { // webpackBootstrap
|
||||
/******/ "use strict";
|
||||
/******/ var __webpack_modules__ = ({});
|
||||
/************************************************************************/
|
||||
/******/ // The module cache
|
||||
/******/ var __webpack_module_cache__ = {};
|
||||
/******/
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
/******/ // Check if module is in cache
|
||||
/******/ var cachedModule = __webpack_module_cache__[moduleId];
|
||||
/******/ if (cachedModule !== undefined) {
|
||||
/******/ return cachedModule.exports;
|
||||
/******/ }
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = __webpack_module_cache__[moduleId] = {
|
||||
/******/ // no module.id needed
|
||||
/******/ // no module.loaded needed
|
||||
/******/ exports: {}
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Execute the module function
|
||||
/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||||
/******/
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
/******/
|
||||
/******/ // expose the modules object (__webpack_modules__)
|
||||
/******/ __webpack_require__.m = __webpack_modules__;
|
||||
/******/
|
||||
/************************************************************************/
|
||||
/******/ /* webpack/runtime/chunk loaded */
|
||||
/******/ (() => {
|
||||
/******/ var deferred = [];
|
||||
/******/ __webpack_require__.O = (result, chunkIds, fn, priority) => {
|
||||
/******/ if(chunkIds) {
|
||||
/******/ priority = priority || 0;
|
||||
/******/ for(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];
|
||||
/******/ deferred[i] = [chunkIds, fn, priority];
|
||||
/******/ return;
|
||||
/******/ }
|
||||
/******/ var notFulfilled = Infinity;
|
||||
/******/ for (var i = 0; i < deferred.length; i++) {
|
||||
/******/ var [chunkIds, fn, priority] = deferred[i];
|
||||
/******/ var fulfilled = true;
|
||||
/******/ for (var j = 0; j < chunkIds.length; j++) {
|
||||
/******/ if ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(__webpack_require__.O).every((key) => (__webpack_require__.O[key](chunkIds[j])))) {
|
||||
/******/ chunkIds.splice(j--, 1);
|
||||
/******/ } else {
|
||||
/******/ fulfilled = false;
|
||||
/******/ if(priority < notFulfilled) notFulfilled = priority;
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ if(fulfilled) {
|
||||
/******/ deferred.splice(i--, 1)
|
||||
/******/ var r = fn();
|
||||
/******/ if (r !== undefined) result = r;
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ return result;
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/compat get default export */
|
||||
/******/ (() => {
|
||||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||
/******/ __webpack_require__.n = (module) => {
|
||||
/******/ var getter = module && module.__esModule ?
|
||||
/******/ () => (module['default']) :
|
||||
/******/ () => (module);
|
||||
/******/ __webpack_require__.d(getter, { a: getter });
|
||||
/******/ return getter;
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/define property getters */
|
||||
/******/ (() => {
|
||||
/******/ // define getter functions for harmony exports
|
||||
/******/ __webpack_require__.d = (exports, definition) => {
|
||||
/******/ for(var key in definition) {
|
||||
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
|
||||
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/ensure chunk */
|
||||
/******/ (() => {
|
||||
/******/ __webpack_require__.f = {};
|
||||
/******/ // This file contains only the entry chunk.
|
||||
/******/ // The chunk loading function for additional chunks
|
||||
/******/ __webpack_require__.e = (chunkId) => {
|
||||
/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => {
|
||||
/******/ __webpack_require__.f[key](chunkId, promises);
|
||||
/******/ return promises;
|
||||
/******/ }, []));
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/get javascript chunk filename */
|
||||
/******/ (() => {
|
||||
/******/ // This function allow to reference async chunks
|
||||
/******/ __webpack_require__.u = (chunkId) => {
|
||||
/******/ // return url for filenames based on template
|
||||
/******/ return "" + chunkId + ".dev.js";
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/global */
|
||||
/******/ (() => {
|
||||
/******/ __webpack_require__.g = (function() {
|
||||
/******/ if (typeof globalThis === 'object') return globalThis;
|
||||
/******/ try {
|
||||
/******/ return this || new Function('return this')();
|
||||
/******/ } catch (e) {
|
||||
/******/ if (typeof window === 'object') return window;
|
||||
/******/ }
|
||||
/******/ })();
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/hasOwnProperty shorthand */
|
||||
/******/ (() => {
|
||||
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/load script */
|
||||
/******/ (() => {
|
||||
/******/ var inProgress = {};
|
||||
/******/ var dataWebpackPrefix = "tinode-webapp:";
|
||||
/******/ // loadScript function to load a script via script tag
|
||||
/******/ __webpack_require__.l = (url, done, key, chunkId) => {
|
||||
/******/ if(inProgress[url]) { inProgress[url].push(done); return; }
|
||||
/******/ var script, needAttach;
|
||||
/******/ if(key !== undefined) {
|
||||
/******/ var scripts = document.getElementsByTagName("script");
|
||||
/******/ for(var i = 0; i < scripts.length; i++) {
|
||||
/******/ var s = scripts[i];
|
||||
/******/ if(s.getAttribute("src") == url || s.getAttribute("data-webpack") == dataWebpackPrefix + key) { script = s; break; }
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ if(!script) {
|
||||
/******/ needAttach = true;
|
||||
/******/ script = document.createElement('script');
|
||||
/******/
|
||||
/******/ script.charset = 'utf-8';
|
||||
/******/ script.timeout = 120;
|
||||
/******/ if (__webpack_require__.nc) {
|
||||
/******/ script.setAttribute("nonce", __webpack_require__.nc);
|
||||
/******/ }
|
||||
/******/ script.setAttribute("data-webpack", dataWebpackPrefix + key);
|
||||
/******/ script.src = url;
|
||||
/******/ }
|
||||
/******/ inProgress[url] = [done];
|
||||
/******/ var onScriptComplete = (prev, event) => {
|
||||
/******/ // avoid mem leaks in IE.
|
||||
/******/ script.onerror = script.onload = null;
|
||||
/******/ clearTimeout(timeout);
|
||||
/******/ var doneFns = inProgress[url];
|
||||
/******/ delete inProgress[url];
|
||||
/******/ script.parentNode && script.parentNode.removeChild(script);
|
||||
/******/ doneFns && doneFns.forEach((fn) => (fn(event)));
|
||||
/******/ if(prev) return prev(event);
|
||||
/******/ };
|
||||
/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000);
|
||||
/******/ script.onerror = onScriptComplete.bind(null, script.onerror);
|
||||
/******/ script.onload = onScriptComplete.bind(null, script.onload);
|
||||
/******/ needAttach && document.head.appendChild(script);
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/make namespace object */
|
||||
/******/ (() => {
|
||||
/******/ // define __esModule on exports
|
||||
/******/ __webpack_require__.r = (exports) => {
|
||||
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
||||
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
||||
/******/ }
|
||||
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/publicPath */
|
||||
/******/ (() => {
|
||||
/******/ __webpack_require__.p = "/umd/";
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/jsonp chunk loading */
|
||||
/******/ (() => {
|
||||
/******/ // no baseURI
|
||||
/******/
|
||||
/******/ // object to store loaded and loading chunks
|
||||
/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched
|
||||
/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded
|
||||
/******/ var installedChunks = {
|
||||
/******/ "runtime": 0
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ __webpack_require__.f.j = (chunkId, promises) => {
|
||||
/******/ // JSONP chunk loading for javascript
|
||||
/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined;
|
||||
/******/ if(installedChunkData !== 0) { // 0 means "already installed".
|
||||
/******/
|
||||
/******/ // a Promise means "currently loading".
|
||||
/******/ if(installedChunkData) {
|
||||
/******/ promises.push(installedChunkData[2]);
|
||||
/******/ } else {
|
||||
/******/ if("runtime" != chunkId) {
|
||||
/******/ // setup Promise in chunk cache
|
||||
/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject]));
|
||||
/******/ promises.push(installedChunkData[2] = promise);
|
||||
/******/
|
||||
/******/ // start chunk loading
|
||||
/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId);
|
||||
/******/ // create error before stack unwound to get useful stacktrace later
|
||||
/******/ var error = new Error();
|
||||
/******/ var loadingEnded = (event) => {
|
||||
/******/ if(__webpack_require__.o(installedChunks, chunkId)) {
|
||||
/******/ installedChunkData = installedChunks[chunkId];
|
||||
/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined;
|
||||
/******/ if(installedChunkData) {
|
||||
/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type);
|
||||
/******/ var realSrc = event && event.target && event.target.src;
|
||||
/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')';
|
||||
/******/ error.name = 'ChunkLoadError';
|
||||
/******/ error.type = errorType;
|
||||
/******/ error.request = realSrc;
|
||||
/******/ installedChunkData[1](error);
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/ __webpack_require__.l(url, loadingEnded, "chunk-" + chunkId, chunkId);
|
||||
/******/ } else installedChunks[chunkId] = 0;
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // no prefetching
|
||||
/******/
|
||||
/******/ // no preloaded
|
||||
/******/
|
||||
/******/ // no HMR
|
||||
/******/
|
||||
/******/ // no HMR manifest
|
||||
/******/
|
||||
/******/ __webpack_require__.O.j = (chunkId) => (installedChunks[chunkId] === 0);
|
||||
/******/
|
||||
/******/ // install a JSONP callback for chunk loading
|
||||
/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => {
|
||||
/******/ var [chunkIds, moreModules, runtime] = data;
|
||||
/******/ // add "moreModules" to the modules object,
|
||||
/******/ // then flag all "chunkIds" as loaded and fire callback
|
||||
/******/ var moduleId, chunkId, i = 0;
|
||||
/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) {
|
||||
/******/ for(moduleId in moreModules) {
|
||||
/******/ if(__webpack_require__.o(moreModules, moduleId)) {
|
||||
/******/ __webpack_require__.m[moduleId] = moreModules[moduleId];
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ if(runtime) var result = runtime(__webpack_require__);
|
||||
/******/ }
|
||||
/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data);
|
||||
/******/ for(;i < chunkIds.length; i++) {
|
||||
/******/ chunkId = chunkIds[i];
|
||||
/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {
|
||||
/******/ installedChunks[chunkId][0]();
|
||||
/******/ }
|
||||
/******/ installedChunks[chunkId] = 0;
|
||||
/******/ }
|
||||
/******/ return __webpack_require__.O(result);
|
||||
/******/ }
|
||||
/******/
|
||||
/******/ var chunkLoadingGlobal = globalThis["webpackChunktinode_webapp"] = globalThis["webpackChunktinode_webapp"] || [];
|
||||
/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
|
||||
/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));
|
||||
/******/ })();
|
||||
/******/
|
||||
/************************************************************************/
|
||||
/******/
|
||||
/******/
|
||||
/******/ })()
|
||||
;
|
||||
//# sourceMappingURL=runtime.dev.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -1,2 +0,0 @@
|
||||
(()=>{"use strict";var e,r,t,o={},n={};function a(e){var r=n[e];if(void 0!==r)return r.exports;var t=n[e]={exports:{}};return o[e].call(t.exports,t,t.exports,a),t.exports}a.m=o,e=[],a.O=(r,t,o,n)=>{if(!t){var i=1/0;for(s=0;s<e.length;s++){for(var[t,o,n]=e[s],l=!0,u=0;u<t.length;u++)(!1&n||i>=n)&&Object.keys(a.O).every((e=>a.O[e](t[u])))?t.splice(u--,1):(l=!1,n<i&&(i=n));if(l){e.splice(s--,1);var d=o();void 0!==d&&(r=d)}}return r}n=n||0;for(var s=e.length;s>0&&e[s-1][2]>n;s--)e[s]=e[s-1];e[s]=[t,o,n]},a.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return a.d(r,{a:r}),r},a.d=(e,r)=>{for(var t in r)a.o(r,t)&&!a.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},a.f={},a.e=e=>Promise.all(Object.keys(a.f).reduce(((r,t)=>(a.f[t](e,r),r)),[])),a.u=e=>e+".prod.js",a.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),a.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),r={},t="tinode-webapp:",a.l=(e,o,n,i)=>{if(r[e])r[e].push(o);else{var l,u;if(void 0!==n)for(var d=document.getElementsByTagName("script"),s=0;s<d.length;s++){var p=d[s];if(p.getAttribute("src")==e||p.getAttribute("data-webpack")==t+n){l=p;break}}l||(u=!0,(l=document.createElement("script")).charset="utf-8",l.timeout=120,a.nc&&l.setAttribute("nonce",a.nc),l.setAttribute("data-webpack",t+n),l.src=e),r[e]=[o];var c=(t,o)=>{l.onerror=l.onload=null,clearTimeout(f);var n=r[e];if(delete r[e],l.parentNode&&l.parentNode.removeChild(l),n&&n.forEach((e=>e(o))),t)return t(o)},f=setTimeout(c.bind(null,void 0,{type:"timeout",target:l}),12e4);l.onerror=c.bind(null,l.onerror),l.onload=c.bind(null,l.onload),u&&document.head.appendChild(l)}},a.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.p="/umd/",(()=>{var e={666:0};a.f.j=(r,t)=>{var o=a.o(e,r)?e[r]:void 0;if(0!==o)if(o)t.push(o[2]);else if(666!=r){var n=new Promise(((t,n)=>o=e[r]=[t,n]));t.push(o[2]=n);var i=a.p+a.u(r),l=new Error;a.l(i,(t=>{if(a.o(e,r)&&(0!==(o=e[r])&&(e[r]=void 0),o)){var n=t&&("load"===t.type?"missing":t.type),i=t&&t.target&&t.target.src;l.message="Loading chunk "+r+" failed.\n("+n+": "+i+")",l.name="ChunkLoadError",l.type=n,l.request=i,o[1](l)}}),"chunk-"+r,r)}else e[r]=0},a.O.j=r=>0===e[r];var r=(r,t)=>{var o,n,[i,l,u]=t,d=0;if(i.some((r=>0!==e[r]))){for(o in l)a.o(l,o)&&(a.m[o]=l[o]);if(u)var s=u(a)}for(r&&r(t);d<i.length;d++)n=i[d],a.o(e,n)&&e[n]&&e[n][0](),e[n]=0;return a.O(s)},t=globalThis.webpackChunktinode_webapp=globalThis.webpackChunktinode_webapp||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})()})();
|
||||
//# sourceMappingURL=runtime.prod.js.map
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1670
-1486
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+3593
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+6358
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
-2175
File diff suppressed because one or more lines are too long
-1
File diff suppressed because one or more lines are too long
+1
-1
@@ -1,3 +1,3 @@
|
||||
// This is a generated file. Don't edit.
|
||||
|
||||
const PACKAGE_VERSION = "0.21.0-rc2";
|
||||
const PACKAGE_VERSION = "0.21.0";
|
||||
|
||||
+2
-1
@@ -59,6 +59,7 @@ module.exports = (env, argv) => {
|
||||
new CopyPlugin({
|
||||
patterns: [
|
||||
{ from: `node_modules/tinode-sdk/umd/tinode.${mode}.js`, to: `tinode.${mode}.js` },
|
||||
{ from: `node_modules/tinode-sdk/umd/tinode.${mode}.js.map`, to: `tinode.${mode}.js.map` },
|
||||
],
|
||||
}),
|
||||
],
|
||||
@@ -66,7 +67,7 @@ module.exports = (env, argv) => {
|
||||
'react': 'React',
|
||||
'react-dom': 'ReactDOM',
|
||||
'react-intl': 'ReactIntl',
|
||||
'tinode-sdk': 'Tinode',
|
||||
'tinode-sdk': 'tinode',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user