add page for user profile view and update endpoints; rename any "rowid" to "rowId"

This commit is contained in:
2025-01-20 12:43:05 -07:00
parent f3f8aeefc3
commit 5763fe4e49
7 changed files with 356 additions and 76 deletions

View File

@@ -158,7 +158,7 @@
We'll just pop the message in only if we discover that they need it.
-->
<div
v-if="!loadingLimits && !endorserLimits?.nextWeekBeginDateTime"
v-if="!isRegistered"
id="noticeBeforeAnnounce"
class="bg-amber-200 text-amber-900 border-amber-500 border-dashed border text-center rounded-md overflow-hidden px-4 py-3 mt-4"
>
@@ -175,6 +175,7 @@
</div>
<div
v-if="isRegistered"
id="sectionNotifications"
class="bg-slate-100 rounded-md overflow-hidden px-4 py-4 mt-8 mb-8"
>
@@ -262,7 +263,10 @@
</div>
<!-- User Profile -->
<div class="bg-slate-100 rounded-md overflow-hidden px-4 py-4 mt-8 mb-8">
<div
v-if="isRegistered"
class="bg-slate-100 rounded-md overflow-hidden px-4 py-4 mt-8 mb-8"
>
<div v-if="loadingProfile" class="text-center mb-2">
<fa icon="spinner" class="fa-spin text-slate-400"></fa> Loading
profile...
@@ -321,22 +325,39 @@
/>
</l-map>
</div>
<button
@click="saveProfile"
class="mt-2 px-4 py-2 bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white rounded-md"
:disabled="loadingProfile || savingProfile"
:class="{
'opacity-50 cursor-not-allowed': loadingProfile || savingProfile,
}"
>
{{
loadingProfile
? "Loading..."
: savingProfile
? "Saving..."
: "Save Profile"
}}
</button>
<div v-if="!loadingProfile && !savingProfile">
<div class="flex justify-between items-center">
<button
@click="saveProfile"
class="mt-2 px-4 py-2 bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white rounded-md"
:disabled="loadingProfile || savingProfile"
:class="{
'opacity-50 cursor-not-allowed': loadingProfile || savingProfile,
}"
>
Save Profile
</button>
<button
@click="confirmDeleteProfile"
class="mt-2 px-4 py-2 bg-gradient-to-b from-red-400 to-red-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white rounded-md"
:disabled="loadingProfile || savingProfile"
:class="{
'opacity-50 cursor-not-allowed':
loadingProfile ||
savingProfile ||
(!userProfileDesc && !includeUserProfileLocation),
}"
>
Delete Profile
</button>
</div>
</div>
<div v-else-if="loadingProfile">
Loading...
</div>
<div v-else="savingProfile">
Saving...
</div>
</div>
<div
@@ -1014,40 +1035,46 @@ export default class AccountViewView extends Vue {
await this.processIdentity();
// Load the user profile
try {
const headers = await getHeaders(this.activeDid);
const response = await this.axios.get(
this.apiServer + "/api/partner/userProfile/" + this.activeDid,
{ headers },
);
if (response.status === 200) {
this.userProfileDesc = response.data.description || "";
this.userProfileLatitude = response.data.locLat || 0;
this.userProfileLongitude = response.data.locLon || 0;
if (this.userProfileLatitude && this.userProfileLongitude) {
this.includeUserProfileLocation = true;
}
} else {
// won't get here because axios throws an error instead
throw Error("Unable to load profile.");
}
} catch (error) {
if (error.status === 404) {
// this is ok: the profile is not yet created
} else {
logConsoleAndDb("Error loading profile: " + errorStringForLog(error));
this.$notify(
{
group: "alert",
type: "danger",
title: "Error Loading Profile",
text: "Your server profile is not available.",
},
5000,
if (this.isRegistered) {
try {
const headers = await getHeaders(this.activeDid);
const response = await this.axios.get(
this.apiServer +
"/api/partner/userProfileForIssuer/" +
this.activeDid,
{ headers },
);
if (response.status === 200) {
this.userProfileDesc = response.data.data.description || "";
this.userProfileLatitude = response.data.data.locLat || 0;
this.userProfileLongitude = response.data.data.locLon || 0;
if (this.userProfileLatitude && this.userProfileLongitude) {
this.includeUserProfileLocation = true;
}
} else {
// won't get here because axios throws an error instead
throw Error("Unable to load profile.");
}
} catch (error) {
if (error.status === 404) {
// this is ok: the profile is not yet created
} else {
logConsoleAndDb(
"Error loading profile: " + errorStringForLog(error),
);
this.$notify(
{
group: "alert",
type: "danger",
title: "Error Loading Profile",
text: "Your server profile is not available.",
},
5000,
);
}
} finally {
this.loadingProfile = false;
}
} finally {
this.loadingProfile = false;
}
} catch (error) {
// this can happen when running automated tests in dev mode because notifications don't work
@@ -1877,5 +1904,64 @@ export default class AccountViewView extends Vue {
this.zoom = 2;
this.includeUserProfileLocation = false;
}
async confirmDeleteProfile() {
this.$notify(
{
group: "modal",
type: "confirm",
title: "Delete Profile",
text: "Are you sure you want to delete your public profile? This will remove your description and location from the server, and it cannot be undone.",
onYes: this.deleteProfile,
},
-1,
);
}
async deleteProfile() {
this.savingProfile = true;
try {
const headers = await getHeaders(this.activeDid);
const response = await this.axios.delete(
this.apiServer + "/api/partner/userProfile",
{ headers },
);
if (response.status === 204) {
this.userProfileDesc = "";
this.userProfileLatitude = 0;
this.userProfileLongitude = 0;
this.includeUserProfileLocation = false;
this.$notify(
{
group: "alert",
type: "success",
title: "Profile Deleted",
text: "Your profile has been deleted successfully.",
},
3000,
);
} else {
throw Error("Profile not deleted");
}
} catch (error) {
logConsoleAndDb("Error deleting profile: " + errorStringForLog(error));
const errorMessage: string =
error.response?.data?.error?.message ||
error.response?.data?.error ||
error.message ||
"There was an error deleting your profile.";
this.$notify(
{
group: "alert",
type: "danger",
title: "Error Deleting Profile",
text: errorMessage,
},
3000,
);
} finally {
this.savingProfile = false;
}
}
}
</script>