Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Social Media Asset Punch List #1027 #1030

Merged
merged 1 commit into from
Aug 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
"@types/leaflet.markercluster": "^1.5.4",
"@vitejs/plugin-vue-jsx": "^4.0.0",
"@vueform/multiselect": "^2.6.7",
"@vuepic/vue-datepicker": "^3.6.8",
"@vuepic/vue-datepicker": "^9.0.1",
"@vueuse/core": "^10.9.0",
"@vueuse/integrations": "^10.9.0",
"@vueuse/math": "^10.9.0",
Expand Down
105 changes: 46 additions & 59 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/App.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<script lang="ts">
import { computed, defineComponent, onMounted, ref, watch } from 'vue';

Check warning on line 2 in src/App.vue

View workflow job for this annotation

GitHub Actions / Lint 💅

'computed' is already defined as a built-in global variable

Check warning on line 2 in src/App.vue

View workflow job for this annotation

GitHub Actions / Lint 💅

'defineComponent' is already defined as a built-in global variable

Check warning on line 2 in src/App.vue

View workflow job for this annotation

GitHub Actions / Lint 💅

'onMounted' is already defined as a built-in global variable

Check warning on line 2 in src/App.vue

View workflow job for this annotation

GitHub Actions / Lint 💅

'ref' is already defined as a built-in global variable

Check warning on line 2 in src/App.vue

View workflow job for this annotation

GitHub Actions / Lint 💅

'watch' is already defined as a built-in global variable
import { useRoute } from 'vue-router';

Check warning on line 3 in src/App.vue

View workflow job for this annotation

GitHub Actions / Lint 💅

'useRoute' is already defined as a built-in global variable
import { useI18n } from 'vue-i18n';

Check warning on line 4 in src/App.vue

View workflow job for this annotation

GitHub Actions / Lint 💅

'useI18n' is already defined as a built-in global variable
import { whenever } from '@vueuse/core';

Check warning on line 5 in src/App.vue

View workflow job for this annotation

GitHub Actions / Lint 💅

'whenever' is already defined as a built-in global variable

Check warning on line 5 in src/App.vue

View workflow job for this annotation

GitHub Actions / Lint 💅

'whenever' is defined but never used
import { useStore } from 'vuex';

Check warning on line 6 in src/App.vue

View workflow job for this annotation

GitHub Actions / Lint 💅

'useStore' is already defined as a built-in global variable
import { DialogWrapper } from 'vue3-promise-dialog';
import axios from 'axios';
import { hash } from './utils/promise';
Expand Down Expand Up @@ -159,7 +159,7 @@

<style lang="scss">
$dp__input_padding: 11px 12px !default;
@import '@vuepic/vue-datepicker/src/VueDatePicker/style/main.scss';
@import '@vuepic/vue-datepicker/dist/main.css';

Check warning on line 162 in src/App.vue

View check run for this annotation

Codecov / codecov/patch

src/App.vue#L162

Added line #L162 was not covered by tests

.crisiscleanup-map-marker svg {
width: 40px;
Expand Down
6 changes: 5 additions & 1 deletion src/components/PdfViewer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
>
</div>
<div class="h-max overflow-y-auto border">
<vue-pdf-embed :source="pdf.full_url" />
<vue-pdf-embed :source="pdf.full_url" :width="width" />

Check warning on line 13 in src/components/PdfViewer.vue

View check run for this annotation

Codecov / codecov/patch

src/components/PdfViewer.vue#L13

Added line #L13 was not covered by tests
</div>
</template>

Expand All @@ -29,6 +29,10 @@
type: Boolean,
default: true,
},
width: {
type: Number,
default: 300,
},

Check warning on line 35 in src/components/PdfViewer.vue

View check run for this annotation

Codecov / codecov/patch

src/components/PdfViewer.vue#L32-L35

Added lines #L32 - L35 were not covered by tests
},
});
</script>
Expand Down
37 changes: 31 additions & 6 deletions src/components/admin/incidents/IncidentAssetBuilder.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,15 @@
:timezone="currentIncident.timezone"
:placeholder="$t('incidentAssets.end_date')"
v-bind="datePickerDefaultProps"
></datepicker>
>
<template #menu-header>
<div
class="my-header flex items-center text-center w-full justify-center mt-3"
>
{{ currentIncident.timezone }}
</div>
</template>
</datepicker>

Check warning on line 68 in src/components/admin/incidents/IncidentAssetBuilder.vue

View check run for this annotation

Codecov / codecov/patch

src/components/admin/incidents/IncidentAssetBuilder.vue#L60-L68

Added lines #L60 - L68 were not covered by tests
<base-select
v-model="selectedAnis"
class="flex-1"
Expand Down Expand Up @@ -355,6 +363,7 @@
format: 'yyyy-MM-dd HH:mm:ss',
autoApply: true,
enableSeconds: true,
weekStart: 0,

Check warning on line 366 in src/components/admin/incidents/IncidentAssetBuilder.vue

View check run for this annotation

Codecov / codecov/patch

src/components/admin/incidents/IncidentAssetBuilder.vue#L366

Added line #L366 was not covered by tests
});

const anis = computed(() => props.anis);
Expand Down Expand Up @@ -391,12 +400,16 @@
if (size(translations) > 0) {
setLocaleMessage(language.subtag, translations);
}
const endDate = moment(ani.end_at)
.subtract(((moment(ani.end_at).day() + 1) % 7) + 1, 'days')
.format('dddd, MMMM D, YYYY');

Check warning on line 406 in src/components/admin/incidents/IncidentAssetBuilder.vue

View check run for this annotation

Codecov / codecov/patch

src/components/admin/incidents/IncidentAssetBuilder.vue#L403-L406

Added lines #L403 - L406 were not covered by tests
const englishValues = {
header: 'CRISISCLEANUP.ORG',
incident_name: `${incident?.name.toUpperCase()} CLEANUP HOTLINE`,
phone_number: formatNationalNumber(ani.phone_number?.toString()),
assistance: `If you need help cleaning up damage from the ${incident?.name}, call ${ani.phone_number?.toString()} to ask for help. We will connect you with volunteers from local relief organizations, community groups and faith communities who may be able to assist with:`,
hotline_text: `All services are free, but service is not guaranteed due to the overwhelming need. This hotline will remain open through ${ani.end_at}.`,
assistance: `If you need help cleaning up damage from the ${incident?.name}, call ${formatNationalNumber(ani.phone_number?.toString())} to ask for help. We will connect you with volunteers from local relief organizations, community groups and faith communities who may be able to assist with:`,
hotline_text: `All services are free, but service is not guaranteed due to the overwhelming need. This hotline will remain open through ${endDate}.`,

Check warning on line 412 in src/components/admin/incidents/IncidentAssetBuilder.vue

View check run for this annotation

Codecov / codecov/patch

src/components/admin/incidents/IncidentAssetBuilder.vue#L411-L412

Added lines #L411 - L412 were not covered by tests
notes_text:
'PLEASE NOTE: this hotline CANNOT assist with social services such as food, clothing, shelter, insurance, or questions about FEMA registration. Volunteers work free of charge and provide the tools and equipment necessary to complete the work.',
work_types: selectedWorkTypes.value
Expand Down Expand Up @@ -572,7 +585,7 @@
}),
);

await getAssets();
await getAssets(type);

Check warning on line 588 in src/components/admin/incidents/IncidentAssetBuilder.vue

View check run for this annotation

Codecov / codecov/patch

src/components/admin/incidents/IncidentAssetBuilder.vue#L588

Added line #L588 was not covered by tests

await $toasted.success(t('info.upload_file_successful'));
};
Expand Down Expand Up @@ -696,7 +709,7 @@
return ani ? ani.phone_number : '';
}

async function getAssets() {
async function getAssets(type = '') {

Check warning on line 712 in src/components/admin/incidents/IncidentAssetBuilder.vue

View check run for this annotation

Codecov / codecov/patch

src/components/admin/incidents/IncidentAssetBuilder.vue#L712

Added line #L712 was not covered by tests
const response = await axios.get(
`${import.meta.env.VITE_APP_API_BASE_URL}/incident_assets`,
{
Expand All @@ -705,7 +718,19 @@
},
},
);
assets.value = response.data.results;

if (type) {
assets.value = assets.value.filter(
(asset) => asset.asset_type !== type,
);
assets.value = assets.value.concat(
response.data.results.filter(
(asset: IncidentAniAsset) => asset.asset_type === type,
),
);
} else {
assets.value = response.data.results;
}

Check warning on line 733 in src/components/admin/incidents/IncidentAssetBuilder.vue

View check run for this annotation

Codecov / codecov/patch

src/components/admin/incidents/IncidentAssetBuilder.vue#L721-L733

Added lines #L721 - L733 were not covered by tests
}

const publishAsset = async (asset: IncidentAniAsset) => {
Expand Down
1 change: 1 addition & 0 deletions src/components/admin/incidents/IncidentForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@
format: 'yyyy-MM-dd HH:mm:ss',
autoApply: true,
enableSeconds: true,
weekStart: 0,

Check warning on line 250 in src/components/admin/incidents/IncidentForm.vue

View check run for this annotation

Codecov / codecov/patch

src/components/admin/incidents/IncidentForm.vue#L250

Added line #L250 was not covered by tests
});
const incidentTypeOptions = INCIDENT_TYPES.map((key) => {
return {
Expand Down
12 changes: 10 additions & 2 deletions src/components/wizard/Wizard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,14 @@
type: Boolean,
default: false,
},
isCompleted: {
type: Boolean,
default: false,
},

Check warning on line 118 in src/components/wizard/Wizard.vue

View check run for this annotation

Codecov / codecov/patch

src/components/wizard/Wizard.vue#L115-L118

Added lines #L115 - L118 were not covered by tests
},
emits: ['done'],

setup(_, { slots, emit }) {
setup(props, { slots, emit }) {

Check warning on line 122 in src/components/wizard/Wizard.vue

View check run for this annotation

Codecov / codecov/patch

src/components/wizard/Wizard.vue#L122

Added line #L122 was not covered by tests
const $toasted = useToast();

const state = reactive({
Expand All @@ -133,7 +137,11 @@
};

function goToStep(index: number) {
if (state.selectedIndex >= index || state.completedSteps.has(index)) {
if (
state.selectedIndex >= index ||
state.completedSteps.has(index) ||
props.isCompleted
) {

Check warning on line 144 in src/components/wizard/Wizard.vue

View check run for this annotation

Codecov / codecov/patch

src/components/wizard/Wizard.vue#L140-L144

Added lines #L140 - L144 were not covered by tests
selectStep(index);
}
}
Expand Down
1 change: 1 addition & 0 deletions src/components/work/WorksiteFilters.vue
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,7 @@
const datePickerDefaultProps = reactive({
format: 'yyyy-MM-dd',
autoApply: true,
weekStart: 0,

Check warning on line 748 in src/components/work/WorksiteFilters.vue

View check run for this annotation

Codecov / codecov/patch

src/components/work/WorksiteFilters.vue#L748

Added line #L748 was not covered by tests
});
const currentSection = ref('general');
const expanded = ref({});
Expand Down
2 changes: 1 addition & 1 deletion src/filters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export function formatRecurrence(date: string) {
return formatDateString(date, 'ddd MMMM Do YYYY [at] h:mm A');
}

export function momentFromNow(date: string) {
export function momentFromNow(date: string | moment.Moment) {
return moment(date).fromNow();
}

Expand Down
1 change: 1 addition & 0 deletions src/models/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ export interface CCUFileItem {
url: string;
full_url: string;
blog_url: string;
general_file_url: string;
large_thumbnail_url: string;
small_thumbnail_url: string;
filename_original: string;
Expand Down
1 change: 1 addition & 0 deletions src/pages/admin/AdminIncidentWizard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
step-default-classes="flex items-center justify-center h-8 cursor-pointer px-2"
step-active-classes=""
:loading="loading"
:is-completed="Boolean(savedIncident)"

Check warning on line 18 in src/pages/admin/AdminIncidentWizard.vue

View check run for this annotation

Codecov / codecov/patch

src/pages/admin/AdminIncidentWizard.vue#L18

Added line #L18 was not covered by tests
@done="onCompletedIncident"
>
<Step
Expand Down
96 changes: 75 additions & 21 deletions src/pages/unauthenticated/disasters/Disasters.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,29 +27,62 @@
<div class="text-lg mb-3 opacity-60">
{{ moment(incident.start_at).format('MMMM Y') }}
</div>
<div
v-if="
incidentAniMap[incident.id] &&
incidentAniMap[incident.id].length > 0
"
class="grid items-center gap-2"
>
<div class="inline-block items-center overflow-hidden">

Check warning on line 30 in src/pages/unauthenticated/disasters/Disasters.vue

View check run for this annotation

Codecov / codecov/patch

src/pages/unauthenticated/disasters/Disasters.vue#L30

Added line #L30 was not covered by tests
<div
v-for="ani in incidentAniMap[incident.id]"
:key="ani.id"
class="flex gap-3 items-center"
v-if="
incidentAniMap[incident.id] &&
incidentAniMap[incident.id].length > 0
"
class="grid items-center gap-2"

Check warning on line 36 in src/pages/unauthenticated/disasters/Disasters.vue

View check run for this annotation

Codecov / codecov/patch

src/pages/unauthenticated/disasters/Disasters.vue#L32-L36

Added lines #L32 - L36 were not covered by tests
>
<a
class="bg-primary-light bg-opacity-30 py-1 px-3 rounded-full"
:href="`tel:${ani.phone_number}`"
<div
v-for="ani in incidentAniMap[incident.id]"
:key="ani.id"
class="flex gap-3 items-center"

Check warning on line 41 in src/pages/unauthenticated/disasters/Disasters.vue

View check run for this annotation

Codecov / codecov/patch

src/pages/unauthenticated/disasters/Disasters.vue#L38-L41

Added lines #L38 - L41 were not covered by tests
>
{{ $t('disasters.hotline') }}
{{ formatNationalNumber(String(ani.phone_number)) }}
</a>
<span class="italic opacity-50 text-sm">
{{ $t('disasters.hotline_closes_in') }}
{{ momentFromNow(ani.end_at) }}
</span>
<a
class="bg-primary-light bg-opacity-30 py-1 px-3 rounded-full"
:href="`tel:${ani.phone_number}`"
>
{{ $t('disasters.hotline') }}
{{ formatNationalNumber(String(ani.phone_number)) }}
</a>
<span class="italic opacity-50 text-sm">
{{ $t('disasters.hotline_closes_in') }}
{{ momentFromNow(getAniClosingDate(ani)) }}
</span>
</div>
</div>
<div v-if="incidentsAssetsMap[incident.id]">
<div class="flex mt-4 items-end">
<template v-for="assetGroup in incidentsAssetsMap[incident.id]">
<div
v-for="asset in assetGroup.filter(
(a) => a.files.length > 0,
)"
:key="`${asset.asset_type}:${asset.language}:${asset.ani}`"
class="p-3 w-min cursor-pointer"
>
<PdfViewer
v-if="
asset.files[0].mime_content_type === 'application/pdf'
"
:pdf="asset.files[0]"
:show-download-button="false"
:width="75"
/>
<img
v-else
:src="asset.files[0].general_file_url"
:alt="asset.files[0].filename"
class="h-18 max-w-84"
/>
<div class="mt-2 w-min">
<LanguageTag :language-id="asset.language" />
</div>
</div>
</template>
</div>

Check warning on line 85 in src/pages/unauthenticated/disasters/Disasters.vue

View check run for this annotation

Codecov / codecov/patch

src/pages/unauthenticated/disasters/Disasters.vue#L43-L85

Added lines #L43 - L85 were not covered by tests
</div>
</div>
</div>
Expand Down Expand Up @@ -105,7 +138,7 @@

<script setup lang="ts">
import Home from '@/layouts/Home.vue';
import { ref, onMounted } from 'vue';
import { onMounted, ref } from 'vue';

Check warning on line 141 in src/pages/unauthenticated/disasters/Disasters.vue

View check run for this annotation

Codecov / codecov/patch

src/pages/unauthenticated/disasters/Disasters.vue#L141

Added line #L141 was not covered by tests
import moment from 'moment/moment';
import type Incident from '@/models/Incident';
import type { AxiosResponse } from 'axios';
Expand All @@ -116,6 +149,11 @@
import AccordionItem from '@/components/accordion/AccordionItem.vue';
import type { Ani } from '@/models/types';
import Spinner from '@/components/Spinner.vue';
import type { GroupedAssets } from '@/components/admin/incidents/IncidentAssetBuilder.vue';
import { hash } from '@/utils/promise';
import { getAssets } from '@/utils/incident_assets';
import PdfViewer from '@/components/PdfViewer.vue';
import LanguageTag from '@/components/tags/LanguageTag.vue';

Check warning on line 156 in src/pages/unauthenticated/disasters/Disasters.vue

View check run for this annotation

Codecov / codecov/patch

src/pages/unauthenticated/disasters/Disasters.vue#L152-L156

Added lines #L152 - L156 were not covered by tests

interface Faq {
name: string;
Expand All @@ -126,6 +164,7 @@
const loading = ref(false);
const incidents = ref<Incident[]>([]);
const incidentAniMap = ref<Record<number, Ani[]>>({});
const incidentsAssetsMap = ref<Record<number, GroupedAssets>>({});

Check warning on line 167 in src/pages/unauthenticated/disasters/Disasters.vue

View check run for this annotation

Codecov / codecov/patch

src/pages/unauthenticated/disasters/Disasters.vue#L167

Added line #L167 was not covered by tests
const faqs: Faq[] = [
{
name: 'survivor.what_is_ccu',
Expand Down Expand Up @@ -186,6 +225,18 @@
},
];

const getAniClosingDate = (ani: Ani) =>
moment(ani.end_at).subtract(((moment(ani.end_at).day() + 1) % 7) + 1, 'days');

async function fetchAllAssets() {
const promises = incidents.value.reduce((acc, incident) => {
acc[incident.id] = getAssets(incident.id);
return acc;
}, {});

return await hash(promises);
}

Check warning on line 239 in src/pages/unauthenticated/disasters/Disasters.vue

View check run for this annotation

Codecov / codecov/patch

src/pages/unauthenticated/disasters/Disasters.vue#L228-L239

Added lines #L228 - L239 were not covered by tests
onMounted(async () => {
loading.value = true;
const response: AxiosResponse<{ results: Incident[] }> = await axios.get(
Expand Down Expand Up @@ -215,6 +266,9 @@

incidentAniMap.value[incident.id] = aniIncidents;
}

incidentsAssetsMap.value = await fetchAllAssets();

Check warning on line 271 in src/pages/unauthenticated/disasters/Disasters.vue

View check run for this annotation

Codecov / codecov/patch

src/pages/unauthenticated/disasters/Disasters.vue#L269-L271

Added lines #L269 - L271 were not covered by tests
loading.value = false;
});
</script>
Expand Down
12 changes: 6 additions & 6 deletions src/templates/incident_asset_templates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@
return result;
};

const handbillTemplate = `<div style="position: relative; width: 800px; height: 255px">
const handbillTemplate = `<div style="position: relative; width: 800px; height: 255px; border-bottom: 1px dotted black;">

Check warning on line 18 in src/templates/incident_asset_templates.ts

View check run for this annotation

Codecov / codecov/patch

src/templates/incident_asset_templates.ts#L18

Added line #L18 was not covered by tests
<div
style="position: absolute; background: black"
style="position: absolute; background: black;"

Check warning on line 20 in src/templates/incident_asset_templates.ts

View check run for this annotation

Codecov / codecov/patch

src/templates/incident_asset_templates.ts#L20

Added line #L20 was not covered by tests
>
<svg width="40" height="250" xmlns="http://www.w3.org/2000/svg">
<text x="-240" y="30" transform="rotate(-90)" font-size="23" fill="white">CRISISCLEANUP.ORG</text>
</svg>
</div>
<div style="margin-left: 2.5rem; line-height: 18px">
<div style="margin-left: 2.5rem; line-height: 18px;">

Check warning on line 26 in src/templates/incident_asset_templates.ts

View check run for this annotation

Codecov / codecov/patch

src/templates/incident_asset_templates.ts#L26

Added line #L26 was not covered by tests
<div style="padding: 1rem 0.5rem; text-align: justify;">
<div style="text-align: center; font-size: 1.75rem; font-weight: 1000;margin-bottom: 10px; line-height: 25px"">{{incident_name}} : <span style="white-space: nowrap">{{phone_number}}</span></div>
<span style="font-size: 0.8rem;">{{assistance}}</span>
Expand All @@ -46,7 +46,7 @@
{{phone_number}}
</div>
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center;">
<div style="display: flex; flex-direction: column; font-size: 0.875rem;">{{work_types}}</div>
<div style="display: grid; grid-template-rows: 1fr; grid-template-columns: repeat(2, 1fr); font-size: 0.875rem; gap: 10px">{{work_types}}</div>

Check warning on line 49 in src/templates/incident_asset_templates.ts

View check run for this annotation

Codecov / codecov/patch

src/templates/incident_asset_templates.ts#L49

Added line #L49 was not covered by tests
<div style="margin-top: 0.25rem; padding: 0.25rem; font-size: 0.75rem; text-align: center">{{hotline_text}}</div>
<div style="display: flex; width: 100%; align-items: center; justify-content: center; padding: 0.75rem;">${logo}</div>
<div style="display: flex; height: 100%; width: 100%; align-items: center; justify-content: center; background-color: #FFC947; text-align: center; font-size: 1.25rem; font-weight: 800; letter-spacing: 0.05em; color: black;">{{header}}</div>
Expand All @@ -60,7 +60,7 @@

const socialMediaTemplate = `<div style="position: relative; height: 100%; border-width: 1px; width: 600px; height: 430px">
<div
style="position: absolute; display: flex; height: 100%; width: 3rem; transform: scale(1); align-items: center; justify-content: center; background-color: #FDB44B; text-align: center; font-size: 1.5rem; font-weight: 800; color: black; writing-mode: vertical-rl;"
style="position: absolute; display: flex; height: 100%; width: 3rem; transform: scale(-1); align-items: center; justify-content: center; background-color: #FDB44B; text-align: center; font-size: 1.5rem; font-weight: 800; color: black; writing-mode: vertical-rl;"

Check warning on line 63 in src/templates/incident_asset_templates.ts

View check run for this annotation

Codecov / codecov/patch

src/templates/incident_asset_templates.ts#L63

Added line #L63 was not covered by tests
>
{{header}}
</div>
Expand All @@ -79,7 +79,7 @@
</div>
</div>`;

const pullTabFlyerTemplate = `<div style="position: relative; width: 800px; height: 1085px; margin: 0.25rem">
const pullTabFlyerTemplate = `<div style="position: relative; width: 800px; height: 1085px; margin: 0.5rem">

Check warning on line 82 in src/templates/incident_asset_templates.ts

View check run for this annotation

Codecov / codecov/patch

src/templates/incident_asset_templates.ts#L82

Added line #L82 was not covered by tests
<div style="display: flex; width: 100%; align-items: center; justify-content: center; padding: 3px;">${logo}</div>
<div style="margin-bottom: 1rem; text-align: center; font-size: 2.5rem; font-weight: 1000;">{{incident_name}} <br>{{phone_number}}</div>
<div style="text-align: center; display: flex; flex-direction: column; justify-content: space-between">
Expand Down
Loading