|
|
@ -255,6 +255,7 @@ |
|
|
|
</table> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div v-else>The changes did not affect essential project data.</div> |
|
|
|
<!-- New line that appears on hover --> |
|
|
|
<div |
|
|
|
class="absolute left-0 w-full text-left text-gray-500 text-sm hidden group-hover:flex cursor-pointer items-center" |
|
|
@ -290,6 +291,7 @@ import { |
|
|
|
} from "../interfaces/records"; |
|
|
|
import { |
|
|
|
didInfo, |
|
|
|
didInfoOrNobody, |
|
|
|
displayAmount, |
|
|
|
getNewOffersToUser, |
|
|
|
getNewOffersToUserProjects, |
|
|
@ -413,7 +415,7 @@ export default class NewActivityView extends Vue { |
|
|
|
async expandOffersToUserAndMarkRead() { |
|
|
|
this.showOffersDetails = !this.showOffersDetails; |
|
|
|
if (this.showOffersDetails) { |
|
|
|
await this.$updateSettings({ |
|
|
|
await this.$saveUserSettings(this.activeDid, { |
|
|
|
lastAckedOfferToUserJwtId: this.newOffersToUser[0].jwtId, |
|
|
|
}); |
|
|
|
// note that we don't update this.lastAckedOfferToUserJwtId in case they |
|
|
@ -431,12 +433,12 @@ export default class NewActivityView extends Vue { |
|
|
|
); |
|
|
|
if (index !== -1 && index < this.newOffersToUser.length - 1) { |
|
|
|
// Set to the next offer's jwtId |
|
|
|
await this.$updateSettings({ |
|
|
|
await this.$saveUserSettings(this.activeDid, { |
|
|
|
lastAckedOfferToUserJwtId: this.newOffersToUser[index + 1].jwtId, |
|
|
|
}); |
|
|
|
} else { |
|
|
|
// it's the last entry (or not found), so just keep it the same |
|
|
|
await this.$updateSettings({ |
|
|
|
await this.$saveUserSettings(this.activeDid, { |
|
|
|
lastAckedOfferToUserJwtId: this.lastAckedOfferToUserJwtId, |
|
|
|
}); |
|
|
|
} |
|
|
@ -450,7 +452,7 @@ export default class NewActivityView extends Vue { |
|
|
|
this.showOffersToUserProjectsDetails = |
|
|
|
!this.showOffersToUserProjectsDetails; |
|
|
|
if (this.showOffersToUserProjectsDetails) { |
|
|
|
await this.$updateSettings({ |
|
|
|
await this.$saveUserSettings(this.activeDid, { |
|
|
|
lastAckedOfferToUserProjectsJwtId: |
|
|
|
this.newOffersToUserProjects[0].jwtId, |
|
|
|
}); |
|
|
@ -469,13 +471,13 @@ export default class NewActivityView extends Vue { |
|
|
|
); |
|
|
|
if (index !== -1 && index < this.newOffersToUserProjects.length - 1) { |
|
|
|
// Set to the next offer's jwtId |
|
|
|
await this.$updateSettings({ |
|
|
|
await this.$saveUserSettings(this.activeDid, { |
|
|
|
lastAckedOfferToUserProjectsJwtId: |
|
|
|
this.newOffersToUserProjects[index + 1].jwtId, |
|
|
|
}); |
|
|
|
} else { |
|
|
|
// it's the last entry (or not found), so just keep it the same |
|
|
|
await this.$updateSettings({ |
|
|
|
await this.$saveUserSettings(this.activeDid, { |
|
|
|
lastAckedOfferToUserProjectsJwtId: |
|
|
|
this.lastAckedOfferToUserProjectsJwtId, |
|
|
|
}); |
|
|
@ -493,7 +495,7 @@ export default class NewActivityView extends Vue { |
|
|
|
this.showStarredProjectChangesDetails && |
|
|
|
this.newStarredProjectChanges.length > 0 |
|
|
|
) { |
|
|
|
await this.$updateSettings({ |
|
|
|
await this.$saveUserSettings(this.activeDid, { |
|
|
|
lastAckedStarredProjectChangesJwtId: |
|
|
|
this.newStarredProjectChanges[0].plan.jwtId, |
|
|
|
}); |
|
|
@ -510,13 +512,13 @@ export default class NewActivityView extends Vue { |
|
|
|
); |
|
|
|
if (index !== -1 && index < this.newStarredProjectChanges.length - 1) { |
|
|
|
// Set to the next change's jwtId |
|
|
|
await this.$updateSettings({ |
|
|
|
await this.$saveUserSettings(this.activeDid, { |
|
|
|
lastAckedStarredProjectChangesJwtId: |
|
|
|
this.newStarredProjectChanges[index + 1].plan.jwtId, |
|
|
|
}); |
|
|
|
} else { |
|
|
|
// it's the last entry (or not found), so just keep it the same |
|
|
|
await this.$updateSettings({ |
|
|
|
await this.$saveUserSettings(this.activeDid, { |
|
|
|
lastAckedStarredProjectChangesJwtId: |
|
|
|
this.lastAckedStarredProjectChangesJwtId, |
|
|
|
}); |
|
|
@ -527,19 +529,6 @@ export default class NewActivityView extends Vue { |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Normalizes values for comparison - treats null, undefined, and empty string as equivalent |
|
|
|
* |
|
|
|
* @param value The value to normalize |
|
|
|
* @returns The normalized value (null for null/undefined/empty, otherwise the original value) |
|
|
|
*/ |
|
|
|
normalizeValueForComparison(value: unknown): unknown { |
|
|
|
if (value === null || value === undefined || value === "") { |
|
|
|
return null; |
|
|
|
} |
|
|
|
return value; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Analyzes differences between current plans and their previous claims |
|
|
|
* |
|
|
@ -554,7 +543,6 @@ export default class NewActivityView extends Vue { |
|
|
|
this.planDifferences = {}; |
|
|
|
|
|
|
|
for (const planChange of planChanges) { |
|
|
|
console.log("planChange", planChange); |
|
|
|
const currentPlan: PlanSummaryRecord = planChange.plan; |
|
|
|
const wrappedClaim: GenericCredWrapper<PlanActionClaim> = |
|
|
|
planChange.wrappedClaimBefore; |
|
|
@ -562,7 +550,7 @@ export default class NewActivityView extends Vue { |
|
|
|
// Extract the actual claim from the wrapped claim |
|
|
|
let previousClaim: PlanActionClaim; |
|
|
|
|
|
|
|
const embeddedClaim: string = wrappedClaim.claim; |
|
|
|
const embeddedClaim: PlanActionClaim = wrappedClaim.claim; |
|
|
|
if ( |
|
|
|
embeddedClaim && |
|
|
|
typeof embeddedClaim === "object" && |
|
|
@ -611,10 +599,14 @@ export default class NewActivityView extends Vue { |
|
|
|
} |
|
|
|
|
|
|
|
// Compare location (combine latitude and longitude into one row) |
|
|
|
const oldLat = previousClaim.location?.geo?.latitude; |
|
|
|
const oldLon = previousClaim.location?.geo?.longitude; |
|
|
|
const newLat = currentPlan.locLat; |
|
|
|
const newLon = currentPlan.locLon; |
|
|
|
const oldLat = this.normalizeValueForComparison( |
|
|
|
previousClaim.location?.geo?.latitude, |
|
|
|
); |
|
|
|
const oldLon = this.normalizeValueForComparison( |
|
|
|
previousClaim.location?.geo?.longitude, |
|
|
|
); |
|
|
|
const newLat = this.normalizeValueForComparison(currentPlan.locLat); |
|
|
|
const newLon = this.normalizeValueForComparison(currentPlan.locLon); |
|
|
|
|
|
|
|
if (!R.equals(oldLat, newLat) || !R.equals(oldLon, newLon)) { |
|
|
|
differences.location = { |
|
|
@ -624,8 +616,18 @@ export default class NewActivityView extends Vue { |
|
|
|
} |
|
|
|
|
|
|
|
// Compare agent (issuer) |
|
|
|
const oldAgent = previousClaim.agent?.identifier; |
|
|
|
const newAgent = currentPlan.agentDid; |
|
|
|
const oldAgent = didInfoOrNobody( |
|
|
|
previousClaim.agent?.identifier, |
|
|
|
this.activeDid, |
|
|
|
this.allMyDids, |
|
|
|
this.allContacts, |
|
|
|
); |
|
|
|
const newAgent = didInfoOrNobody( |
|
|
|
currentPlan.agentDid, |
|
|
|
this.activeDid, |
|
|
|
this.allMyDids, |
|
|
|
this.allContacts, |
|
|
|
); |
|
|
|
const normalizedOldAgent = this.normalizeValueForComparison(oldAgent); |
|
|
|
const normalizedNewAgent = this.normalizeValueForComparison(newAgent); |
|
|
|
if (!R.equals(normalizedOldAgent, normalizedNewAgent)) { |
|
|
@ -639,9 +641,9 @@ export default class NewActivityView extends Vue { |
|
|
|
const oldStartTime = previousClaim.startTime; |
|
|
|
const newStartTime = currentPlan.startTime; |
|
|
|
const normalizedOldStartTime = |
|
|
|
this.normalizeValueForComparison(oldStartTime); |
|
|
|
this.normalizeDateForComparison(oldStartTime); |
|
|
|
const normalizedNewStartTime = |
|
|
|
this.normalizeValueForComparison(newStartTime); |
|
|
|
this.normalizeDateForComparison(newStartTime); |
|
|
|
if (!R.equals(normalizedOldStartTime, normalizedNewStartTime)) { |
|
|
|
differences.startTime = { |
|
|
|
old: oldStartTime, |
|
|
@ -652,8 +654,8 @@ export default class NewActivityView extends Vue { |
|
|
|
// Compare end time |
|
|
|
const oldEndTime = previousClaim.endTime; |
|
|
|
const newEndTime = currentPlan.endTime; |
|
|
|
const normalizedOldEndTime = this.normalizeValueForComparison(oldEndTime); |
|
|
|
const normalizedNewEndTime = this.normalizeValueForComparison(newEndTime); |
|
|
|
const normalizedOldEndTime = this.normalizeDateForComparison(oldEndTime); |
|
|
|
const normalizedNewEndTime = this.normalizeDateForComparison(newEndTime); |
|
|
|
if (!R.equals(normalizedOldEndTime, normalizedNewEndTime)) { |
|
|
|
differences.endTime = { |
|
|
|
old: oldEndTime, |
|
|
@ -705,6 +707,38 @@ export default class NewActivityView extends Vue { |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Normalizes values for comparison - treats null, undefined, and empty string as equivalent |
|
|
|
* |
|
|
|
* @param value The value to normalize |
|
|
|
* @returns The normalized value (null for null/undefined/empty, otherwise the original value) |
|
|
|
*/ |
|
|
|
normalizeValueForComparison<T>(value: T | null | undefined): T | null { |
|
|
|
if (value === null || value === undefined || value === "") { |
|
|
|
return null; |
|
|
|
} |
|
|
|
return value; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Normalizes date values for comparison by converting strings to Date objects |
|
|
|
* Returns null for null/undefined/empty values, Date objects for valid date strings |
|
|
|
*/ |
|
|
|
normalizeDateForComparison(value: unknown): Date | null { |
|
|
|
if (value === null || value === undefined || value === "") { |
|
|
|
return null; |
|
|
|
} |
|
|
|
if (typeof value === "string") { |
|
|
|
const date = new Date(value); |
|
|
|
// Check if the date is valid |
|
|
|
return isNaN(date.getTime()) ? null : date; |
|
|
|
} |
|
|
|
if (value instanceof Date) { |
|
|
|
return isNaN(value.getTime()) ? null : value; |
|
|
|
} |
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Gets the differences for a specific plan by handle ID |
|
|
|
* |
|
|
@ -817,11 +851,11 @@ export default class NewActivityView extends Vue { |
|
|
|
* @returns A formatted location string |
|
|
|
*/ |
|
|
|
formatLocationValue( |
|
|
|
latitude: number | undefined, |
|
|
|
longitude: number | undefined, |
|
|
|
latitude: number | undefined | null, |
|
|
|
longitude: number | undefined | null, |
|
|
|
isOldValue: boolean = false, |
|
|
|
): string { |
|
|
|
if (latitude === undefined && longitude === undefined) { |
|
|
|
if (latitude == null && longitude == null) { |
|
|
|
return "Not set"; |
|
|
|
} |
|
|
|
// If there's any location data, show generic labels instead of coordinates |
|
|
|