mirror of
https://github.com/zoldar/jenot.git
synced 2026-01-03 14:32:54 +00:00
Make sync offline friendly
This commit is contained in:
parent
17c158b6c1
commit
d11d0b0cf1
5 changed files with 41 additions and 41 deletions
|
|
@ -13,6 +13,7 @@ defmodule Jenot.Note do
|
|||
|
||||
belongs_to(:account, Jenot.Account, type: :binary_id)
|
||||
|
||||
field(:server_updated_at, :utc_datetime_usec)
|
||||
timestamps(type: :utc_datetime_usec)
|
||||
end
|
||||
|
||||
|
|
@ -28,6 +29,7 @@ defmodule Jenot.Note do
|
|||
:updated_at
|
||||
])
|
||||
|> put_change(:id, Ecto.UUID.generate())
|
||||
|> put_change(:server_updated_at, DateTime.utc_now())
|
||||
|> validate_required([:internal_id, :type, :inserted_at, :updated_at])
|
||||
|> put_assoc(:account, account)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -11,8 +11,7 @@ defmodule Jenot.Notes do
|
|||
def latest_change(account) do
|
||||
Note
|
||||
|> where(account_id: ^account.id)
|
||||
|> where([n], is_nil(n.deleted_at))
|
||||
|> select([n], max(n.updated_at))
|
||||
|> select([n], max(n.server_updated_at))
|
||||
|> Repo.one()
|
||||
end
|
||||
|
||||
|
|
@ -148,7 +147,7 @@ defmodule Jenot.Notes do
|
|||
|> String.to_integer()
|
||||
|> DateTime.from_unix!(:millisecond)
|
||||
|
||||
where(query, [n], n.updated_at > ^datetime)
|
||||
where(query, [n], n.server_updated_at > ^datetime)
|
||||
end
|
||||
|
||||
defp upsert(changeset, opts) do
|
||||
|
|
@ -195,6 +194,7 @@ defmodule Jenot.Notes do
|
|||
^deleted_at,
|
||||
n.deleted_at
|
||||
),
|
||||
server_updated_at: ^DateTime.utc_now(),
|
||||
updated_at:
|
||||
fragment(
|
||||
"CASE WHEN ? > ? THEN ? ELSE ? END",
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ defmodule Jenot.Repo.Migrations.InitialSchema do
|
|||
|
||||
add :account_id, references(:accounts, on_delete: :delete_all), null: false
|
||||
|
||||
add :server_updated_at, :datetime_usec, null: false
|
||||
timestamps(type: :datetime_usec)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ const sync = async () => {
|
|||
Notes.saveStorage();
|
||||
};
|
||||
|
||||
sync();
|
||||
setInterval(sync, 5000);
|
||||
|
||||
// Notifications API test - to be reused for push notifications later on
|
||||
|
|
@ -57,8 +56,9 @@ const editNote = document.querySelector("#edit-note");
|
|||
// of notes list.
|
||||
Notes.addEventListener("save", render.bind(this));
|
||||
|
||||
// Initial notes render.
|
||||
// Initial notes render and initial sync.
|
||||
render();
|
||||
sync();
|
||||
|
||||
// note-form component specific event handlers
|
||||
newNote.addEventListener("addNote", async (e) => {
|
||||
|
|
|
|||
|
|
@ -12,11 +12,19 @@ class WebNoteStore {
|
|||
params.append("deleted", "true");
|
||||
}
|
||||
const suffix = params.size > 0 ? `?${params.toString()}` : "";
|
||||
return this.#request(`${this.endpoint}api/notes${suffix}`, {}, () => []);
|
||||
return this.#request(
|
||||
`${this.endpoint}api/notes${suffix}`,
|
||||
{},
|
||||
() => "no_network",
|
||||
);
|
||||
}
|
||||
|
||||
async get(id) {
|
||||
return this.#request(`${this.endpoint}api/notes/${id}`, {}, () => null);
|
||||
return this.#request(
|
||||
`${this.endpoint}api/notes/${id}`,
|
||||
{},
|
||||
() => "no_network",
|
||||
);
|
||||
}
|
||||
|
||||
async add(note) {
|
||||
|
|
@ -26,7 +34,7 @@ class WebNoteStore {
|
|||
method: "POST",
|
||||
body: JSON.stringify(note),
|
||||
},
|
||||
() => null,
|
||||
() => "no_network",
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -37,7 +45,7 @@ class WebNoteStore {
|
|||
method: "PUT",
|
||||
body: JSON.stringify(note),
|
||||
},
|
||||
() => null,
|
||||
() => "no_network",
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -174,7 +182,7 @@ export class SyncedNoteStore extends EventTarget {
|
|||
),
|
||||
)
|
||||
.then(() => {
|
||||
(async () => (skipNetwork ? null : this.webStore?.update(note)))();
|
||||
(async () => (skipNetwork ? null : this.webStore?.add(note)))();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
|
@ -183,19 +191,33 @@ export class SyncedNoteStore extends EventTarget {
|
|||
const that = this;
|
||||
const meta = await this.getMeta();
|
||||
const lastSync = meta?.lastSync;
|
||||
const currentSync = Date.now();
|
||||
|
||||
this.all(lastSync, true)
|
||||
.then((notes) => {
|
||||
notes.forEach(async (n) => await that.webStore.add(n));
|
||||
return Promise.all(notes.map((n) => that.webStore.add(n)));
|
||||
})
|
||||
.then((results) => {
|
||||
if (results.indexOf("no_network") < 0) {
|
||||
return that.webStore.all(lastSync, true);
|
||||
} else {
|
||||
return "no_network";
|
||||
}
|
||||
})
|
||||
.then(() => that.webStore.all(lastSync, true))
|
||||
.then((notes) => {
|
||||
notes.forEach(async (n) => await that.update(n, true));
|
||||
if (notes !== "no_network") {
|
||||
notes.forEach(async (n) => await that.update(n, true));
|
||||
return null;
|
||||
} else {
|
||||
return "no_network";
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
meta.lastSync = Date.now();
|
||||
.then((result) => {
|
||||
if (result !== "no_network") {
|
||||
meta.lastSync = currentSync;
|
||||
|
||||
that.setMeta(meta);
|
||||
that.setMeta(meta);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -233,29 +255,4 @@ export class SyncedNoteStore extends EventTarget {
|
|||
};
|
||||
});
|
||||
}
|
||||
|
||||
#request(url, opts, emptyValue) {
|
||||
new Promise((resolve) => {
|
||||
return resolve(this.#runRequest(url, opts, () => emptyValue));
|
||||
});
|
||||
}
|
||||
|
||||
async #runRequest(url, opts, errorCallback) {
|
||||
opts.headers = {
|
||||
...(opts.headers || {}),
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(url, opts);
|
||||
if (!response.ok) {
|
||||
console.error("Request failed", response);
|
||||
return errorCallback(response);
|
||||
}
|
||||
return response.json();
|
||||
} catch (error) {
|
||||
console.error("Request error", error);
|
||||
return errorCallback(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue