Skip to content

Commit

Permalink
feat: Social Media Asset Punch List #1027
Browse files Browse the repository at this point in the history
  • Loading branch information
tabiodun committed Aug 2, 2024
1 parent 0d479b2 commit 871ea2f
Show file tree
Hide file tree
Showing 13 changed files with 180 additions and 98 deletions.
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
Expand Up @@ -159,7 +159,7 @@ export default defineComponent({

<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';
.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" />
</div>
</template>

Expand All @@ -29,6 +29,10 @@ export default defineComponent({
type: Boolean,
default: true,
},
width: {
type: Number,
default: 300,
},
},
});
</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>
<base-select
v-model="selectedAnis"
class="flex-1"
Expand Down Expand Up @@ -355,6 +363,7 @@ export default {
format: 'yyyy-MM-dd HH:mm:ss',
autoApply: true,
enableSeconds: true,
weekStart: 0,
});
const anis = computed(() => props.anis);
Expand Down Expand Up @@ -391,12 +400,16 @@ export default {
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');
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}.`,
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 @@ export default {
}),
);
await getAssets();
await getAssets(type);
await $toasted.success(t('info.upload_file_successful'));
};
Expand Down Expand Up @@ -696,7 +709,7 @@ export default {
return ani ? ani.phone_number : '';
}
async function getAssets() {
async function getAssets(type = '') {
const response = await axios.get(
`${import.meta.env.VITE_APP_API_BASE_URL}/incident_assets`,
{
Expand All @@ -705,7 +718,19 @@ export default {
},
},
);
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;
}
}
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 @@ export default defineComponent({
format: 'yyyy-MM-dd HH:mm:ss',
autoApply: true,
enableSeconds: true,
weekStart: 0,
});
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 @@ export default defineComponent({
type: Boolean,
default: false,
},
isCompleted: {
type: Boolean,
default: false,
},
},
emits: ['done'],
setup(_, { slots, emit }) {
setup(props, { slots, emit }) {
const $toasted = useToast();
const state = reactive({
Expand All @@ -133,7 +137,11 @@ export default defineComponent({
};
function goToStep(index: number) {
if (state.selectedIndex >= index || state.completedSteps.has(index)) {
if (
state.selectedIndex >= index ||
state.completedSteps.has(index) ||
props.isCompleted
) {
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 @@ export default defineComponent({
const datePickerDefaultProps = reactive({
format: 'yyyy-MM-dd',
autoApply: true,
weekStart: 0,
});
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)"
@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">
<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"
>
<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"
>
{{ $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>
</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';
import moment from 'moment/moment';
import type Incident from '@/models/Incident';
import type { AxiosResponse } from 'axios';
Expand All @@ -116,6 +149,11 @@ import Accordion from '@/components/accordion/Accordion.vue';
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';
interface Faq {
name: string;
Expand All @@ -126,6 +164,7 @@ const route = useRoute();
const loading = ref(false);
const incidents = ref<Incident[]>([]);
const incidentAniMap = ref<Record<number, Ani[]>>({});
const incidentsAssetsMap = ref<Record<number, GroupedAssets>>({});
const faqs: Faq[] = [
{
name: 'survivor.what_is_ccu',
Expand Down Expand Up @@ -186,6 +225,18 @@ const faqs: Faq[] = [
},
];
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);
}
onMounted(async () => {
loading.value = true;
const response: AxiosResponse<{ results: Incident[] }> = await axios.get(
Expand Down Expand Up @@ -215,6 +266,9 @@ onMounted(async () => {
incidentAniMap.value[incident.id] = aniIncidents;
}
incidentsAssetsMap.value = await fetchAllAssets();
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 @@ const replacePlaceholders = (
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;">
<div
style="position: absolute; background: black"
style="position: absolute; background: black;"
>
<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;">
<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 @@ const doorHangerTemplate = `<div style="position: relative; border-left: dotted
{{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>
<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 doorHangerTemplate = `<div style="position: relative; border-left: dotted

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;"
>
{{header}}
</div>
Expand All @@ -79,7 +79,7 @@ const socialMediaTemplate = `<div style="position: relative; height: 100%; borde
</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">
<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

0 comments on commit 871ea2f

Please sign in to comment.