preparing storing of new contact
This commit is contained in:
@@ -3,6 +3,7 @@ package de.srsoftware.umbrella.contact;
|
||||
|
||||
import static de.srsoftware.tools.jdbc.Condition.equal;
|
||||
import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL;
|
||||
import static de.srsoftware.tools.jdbc.Query.insertInto;
|
||||
import static de.srsoftware.tools.jdbc.Query.select;
|
||||
import static de.srsoftware.umbrella.contact.Constants.*;
|
||||
import static de.srsoftware.umbrella.core.Constants.*;
|
||||
@@ -92,7 +93,16 @@ public class SqliteDb extends BaseDb implements ContactDb{
|
||||
@Override
|
||||
public Contact save(Contact contact) {
|
||||
if (contact.id() == 0){ // new contact
|
||||
throw UmbrellaException.unprocessable("Storing of new contacts not implemented");
|
||||
try {
|
||||
var rs = insertInto(TABLE_CONTACTS,DATA).values(contact.vcard()).execute(db).getGeneratedKeys();
|
||||
Long id = null;
|
||||
if (rs.next()) id = rs.getLong(1);
|
||||
rs.close();
|
||||
if (id != null) return new Contact(id,contact.vcard());
|
||||
throw databaseException("Failed to store new vcard");
|
||||
} catch (SQLException e) {
|
||||
throw databaseException("Failed to store new vcard",e);
|
||||
}
|
||||
} else try { // update
|
||||
Query.update(TABLE_CONTACTS).set(DATA).where(ID,equal(contact.id())).prepare(db).apply(contact.vcard()).execute();
|
||||
} catch (SQLException e) {
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
import ExtraField from './ExtraField.svelte';
|
||||
import FN from './FN.svelte';
|
||||
import Name from './Name.svelte';
|
||||
import Number from './Number.svelte';
|
||||
import Org from './Org.svelte';
|
||||
import URL from './URL.svelte';
|
||||
|
||||
let { contact } = $props();
|
||||
|
||||
@@ -18,7 +20,9 @@
|
||||
let emails = $derived(contact.vcard.match(/^EMAIL.*:.+$/gm));
|
||||
let extra_fields = $derived(contact.vcard.match(/^X-.*:.+/gm));
|
||||
let fns = $derived(contact.vcard.match(/^FN.*:.+$/gm));
|
||||
let numbers = $derived(contact.vcard.match(/^TEL.*:.+$/gm));
|
||||
let orgs = $derived(contact.vcard.match(/^ORG.*:.+$/gm));
|
||||
let urls = $derived(contact.vcard.match(/^URL.*:.+$/gm));
|
||||
|
||||
async function patch(from,to){
|
||||
if (from == to) return;
|
||||
@@ -44,7 +48,11 @@
|
||||
|
||||
<fieldset class="vcard">
|
||||
<legend>
|
||||
{#if contact.id}
|
||||
{t('contact_number',{number:contact.id})}
|
||||
{:else}
|
||||
{t('new_contact')}
|
||||
{/if}
|
||||
<button class="symbol" onclick={toggleCode}></button>
|
||||
</legend>
|
||||
<table>
|
||||
@@ -81,6 +89,13 @@
|
||||
{/each}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
{#each numbers as code}
|
||||
<Number {code} {patch} />
|
||||
{/each}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
{#each emails as code}
|
||||
@@ -95,6 +110,13 @@
|
||||
{/each}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
{#each urls as code}
|
||||
<URL {code} {patch} />
|
||||
{/each}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</fieldset>
|
||||
@@ -15,6 +15,27 @@
|
||||
yikes();
|
||||
var data = await res.json();
|
||||
contacts = Object.values(data).sort(byName);
|
||||
contacts.unshift({
|
||||
id: 0,
|
||||
vcard: `BEGIN:VCARD
|
||||
VERSION:3.0
|
||||
PRODID:Umbrella Contact manager by SRSoftware
|
||||
FN:${t('formatted_name')}
|
||||
N:${t('family_name')};${t('given_name')};;;
|
||||
ORG:${t('organization')}
|
||||
EMAIL;TYPE=HOME:${t('email')}
|
||||
EMAIL;TYPE=WORK:${t('email')}
|
||||
ADR;TYPE=HOME:;;${t('street')};${t('locality')};${t('region')};${t('post_code')};${t('country')}
|
||||
ADR;TYPE=WORK:;;${t('street')};${t('locality')};${t('region')};${t('post_code')};${t('country')}
|
||||
TEL;TYPE=CELL;:${t('phone_cell')}
|
||||
TEL;TYPE=HOME;:${t('phone_home')}
|
||||
TEL;TYPE=WORK;:${t('phone_work')}
|
||||
X-TAX-NUMBER:${t('tax_id')}
|
||||
X-BANK-ACCOUNT:${t('bank_account')}\\nIBAN:XXXX\\nBIC:XXXX
|
||||
X-COURT:${t('local_court')}
|
||||
URL:https://example.com
|
||||
END:VCARD`
|
||||
});
|
||||
} else {
|
||||
error(res);
|
||||
}
|
||||
|
||||
43
frontend/src/routes/contact/Number.svelte
Normal file
43
frontend/src/routes/contact/Number.svelte
Normal file
@@ -0,0 +1,43 @@
|
||||
<script>
|
||||
import LineEditor from '../../Components/LineEditor.svelte';
|
||||
import { number } from '../../vcard.js';
|
||||
|
||||
let { code, patch = (from, to) => true } = $props();
|
||||
|
||||
let cell = $derived(code.toLowerCase().includes('type=cell'));
|
||||
let home = $derived(code.toLowerCase().includes('type=home'));
|
||||
let work = $derived(code.toLowerCase().includes('type=work'));
|
||||
let value = $derived(number(code));
|
||||
|
||||
function onSet(newVal){
|
||||
const newCode = code.replace(value,newVal);
|
||||
return patch(code,newCode);
|
||||
}
|
||||
|
||||
function toggleCell(){
|
||||
toggleType('CELL');
|
||||
}
|
||||
|
||||
function toggleHome(){
|
||||
toggleType('HOME');
|
||||
}
|
||||
|
||||
function toggleType(key){
|
||||
key = key.toUpperCase();
|
||||
if (code.toUpperCase().includes(';TYPE='+key)) {
|
||||
const regex = new RegExp(';TYPE='+key, "ig");
|
||||
patch(code,code.replace(regex,''));
|
||||
} else patch(code,code.replace('TEL','TEL;TYPE='+key));
|
||||
}
|
||||
|
||||
function toggleWork(){
|
||||
toggleType('WORK');
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if value}
|
||||
<span class="symbol {cell?'':'inactive'}" onclick={toggleCell} ></span>
|
||||
<span class="symbol {home?'':'inactive'}" onclick={toggleHome}></span>
|
||||
<span class="symbol {work?'':'inactive'}" onclick={toggleWork} ></span>
|
||||
<LineEditor type="span" editable={true} {value} {onSet} /><br/>
|
||||
{/if}
|
||||
18
frontend/src/routes/contact/URL.svelte
Normal file
18
frontend/src/routes/contact/URL.svelte
Normal file
@@ -0,0 +1,18 @@
|
||||
<script>
|
||||
import LineEditor from '../../Components/LineEditor.svelte';
|
||||
import { url } from '../../vcard.js';
|
||||
import { t } from '../../translations.svelte';
|
||||
|
||||
let { code, patch = (from, to) => true } = $props();
|
||||
|
||||
let value = $derived(url(code));
|
||||
|
||||
function onSet(newVal){
|
||||
const newCode = code.replace(value,newVal);
|
||||
return patch(code,newCode);
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if value}
|
||||
<LineEditor type="span" editable={true} {value} {onSet} title={t('url')}/>
|
||||
{/if}
|
||||
@@ -37,11 +37,22 @@ export function fn(vcard){
|
||||
return match ? match[1].trim() : '';
|
||||
}
|
||||
|
||||
export function number(vcard){
|
||||
const match = vcard.match(/^TEL.*:(.+)$/m);
|
||||
return match ? match[1].trim() : '';
|
||||
}
|
||||
|
||||
|
||||
export function org(vcard){
|
||||
const match = vcard.match(/^ORG:(.+)$/m);
|
||||
return match ? match[1].trim() : '';
|
||||
}
|
||||
|
||||
export function url(vcard){
|
||||
const match = vcard.match(/^URL:(.+)$/m);
|
||||
return match ? match[1].trim() : '';
|
||||
}
|
||||
|
||||
export function name(vcard){
|
||||
const match = vcard.match(/^N:(.+)$/m);
|
||||
let name = {
|
||||
|
||||
@@ -91,6 +91,7 @@
|
||||
|
||||
"failed": "fehlgeschlagen",
|
||||
"failed_login_attempts" : "Account nach {attempts} fehlgeschlagenen Logins gesperrt bis {release_time}",
|
||||
"family_name": "Familenname",
|
||||
"file": "Datei",
|
||||
"files": "Dateien",
|
||||
"filter": "Filter",
|
||||
@@ -100,6 +101,7 @@
|
||||
"formatted_name": "Anzeigename",
|
||||
"fulltext": "Volltextsuche",
|
||||
|
||||
"given_name": "Vorname",
|
||||
"go": "los!",
|
||||
"go_to_url_to_reset_password": "Um ein neues Passwort zu erhalten, öffnen Sie bitte den folgenden Link: {url}",
|
||||
"gross_sum": "Brutto-Summe",
|
||||
@@ -167,6 +169,7 @@
|
||||
"name": "Name",
|
||||
"net_price": "Nettopreis",
|
||||
"net_sum": "Netto-Summe",
|
||||
"new_contact": "neuer Kontakt",
|
||||
"new_password": "neues Passwort",
|
||||
"new_document_from": "{number} / neues {type}s-Dokument von {sender}",
|
||||
"no_company": "keine Firma",
|
||||
|
||||
Reference in New Issue
Block a user