Skip to content

Commit b92d1d4

Browse files
committed
Edus and Bus are now having slugs for linking, generated from name.
This is to avoid special charaters in URLs that are encoded and encoded once again by server reroutes etc.
1 parent cf93d67 commit b92d1d4

34 files changed

Lines changed: 864 additions & 822 deletions

community-app/frontend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"lodash.debounce": "^4.0.8",
1818
"pinia": "^3.0.3",
1919
"showdown": "^2.1.0",
20+
"slugify": "^1.6.6",
2021
"vue": "^3.5.13",
2122
"vue-router": "^4.5.0"
2223
},

community-app/frontend/src/components/InputField.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { getValue } from "./profile/HelpTexts.js"
66
import { isString } from '../utils.js'
77
88
const model = defineModel();
9-
const props = defineProps(['path', 'type']);
9+
const props = defineProps(['path', 'type', 'disabled']);
1010
1111
const help = ref(getValue(props.path, "help", props.type));
1212
const label = ref(getValue(props.path, "label", props.type));
@@ -21,7 +21,7 @@ const placeholder = ref(getValue(props.path, "placeholder", props.type));
2121
<InfoButton v-if="help" :info="help"/>
2222
</template>
2323
<template #default>
24-
<n-input v-model:value="model" :placeholder="placeholder"/>
24+
<n-input v-model:value="model" :placeholder="placeholder" :disabled="disabled"/>
2525
</template>
2626
</n-form-item>
2727
</template>

community-app/frontend/src/components/Maintains.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ defineProps(['data']);
88
<template>
99
<div>
1010
<div class="mb-2">Maintains:</div>
11-
<a v-if="data.company" :href="'/business/'+data.company.name" @click="(event) => showBusinessProfile(data.company.name, event)">
11+
<a v-if="data.company" :href="'/business/'+data.company.slug" @click="(event) => showBusinessProfile(data.company.slug, event)">
1212
<div class="mb-1 d-flex text-align-center">
1313
{{ data.company.name }}
1414
</div>
1515
</a>
16-
<a v-if="data.edu" :href="'/edu/'+data.edu.name" @click="(event) => showEduProfile(data.edu.name, event)">
16+
<a v-if="data.edu" :href="'/edu/'+data.edu.slug" @click="(event) => showEduProfile(data.edu.slug, event)">
1717
<p class="mb-1">
1818
{{ data.edu.name }}
1919
</p>

community-app/frontend/src/components/overview/Businesses.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ function showAll()
4848
</template>
4949
<template v-else-if="store">
5050
<div v-if="store.items?.length > 0" v-for="item in store.items" class="logo" :key="item.text">
51-
<a :href="item.url" @click="(event)=>showBusinessProfile(item.text, event)">
51+
<a :href="item.url" @click="(event)=>showBusinessProfile(item.slug, event)">
5252
<NTooltip trigger="hover" placement="top">
5353
<template #trigger>
5454
<img :src="item.img || defaultLogo" :alt="item.text"/>

community-app/frontend/src/components/overview/BusinessesStore.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export const useBusinessesStore = defineStore ('businesses',{
3232
async function fetchBusinesses(){
3333

3434
const imageParamsLogos = "?withoutEnlargement=true&quality=98&fit=cover&height=200&format=png";
35-
const url = Constants.GET_COMPANIES+"?fields[]=name,logo&meta=filter_count";
35+
const url = Constants.GET_COMPANIES+"?fields[]=name,logo,slug&meta=filter_count";
3636

3737
const limit = 10;
3838

@@ -44,8 +44,9 @@ async function fetchBusinesses(){
4444
const items = json.data?.map((b) => (
4545
{
4646
img: b.logo ? createAssetUrl(b.logo) + imageParamsLogos : null,
47-
url: '/business/'+b.name,
47+
url: '/business/'+b.slug,
4848
text: b.name,
49+
slug: b.slug
4950
}
5051
));
5152

community-app/frontend/src/components/overview/Edus.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ function showAll()
4848
</template>
4949
<template v-else-if="store">
5050
<div v-if="store.items?.length > 0" v-for="item in store.items" class="logo" :key="item.text">
51-
<a :href="item.url" @click="(event)=>showEduProfile(item.text, event)">
51+
<a :href="item.url" @click="(event)=>showEduProfile(item.slug, event)">
5252
<NTooltip trigger="hover" placement="top">
5353
<template #trigger>
5454
<img :src="item.img || defaultLogo" :alt="item.text"/>

community-app/frontend/src/components/overview/EdusStore.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export const useEdusStore = defineStore ('edus',{
3232
async function fetchEdus(){
3333

3434
const imageParamsLogos = "?withoutEnlargement=true&quality=98&fit=cover&height=200&format=png";
35-
const url = Constants.GET_EDUS+"?fields[]=name,logo&meta=filter_count";
35+
const url = Constants.GET_EDUS+"?fields[]=name,logo,slug&meta=filter_count";
3636

3737
const limit = 10;
3838

@@ -44,8 +44,9 @@ async function fetchEdus(){
4444
const items = json.data?.map((b) => (
4545
{
4646
img: b.logo ? createAssetUrl(b.logo) + imageParamsLogos : null,
47-
url: '/edu/'+b.name,
47+
url: '/edu/'+b.slug,
4848
text: b.name,
49+
slug: b.slug
4950
}
5051
));
5152

community-app/frontend/src/components/profile/Business.vue

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script setup>
22
import { ref, onMounted, computed } from 'vue'
3+
import slugify from 'slugify'
34
import Constants from '../../constants.js'
45
import FileUploader from './FileUploader.vue'
56
import SocialFields from './SocialFields.vue'
@@ -31,6 +32,7 @@ const emptyCompany = {
3132
enabled: false,
3233
logo: null,
3334
name: "",
35+
slug: "",
3436
tagline: "",
3537
description: "",
3638
internships: false,
@@ -89,7 +91,7 @@ const rules = {
8991
message: "Website is required",
9092
trigger: ['input', 'blur'],
9193
validator: (rule, value)=>{
92-
return form.value[0].social.website.length > 0;
94+
return form.value[0]?.social?.website?.length > 0;
9395
}
9496
},
9597
logo: {
@@ -130,6 +132,15 @@ const submit = async () => {
130132
delete formValue.status;
131133
delete formValue.website;
132134
135+
if (!form.value[0].slug)
136+
{
137+
formValue.slug = slug.value;
138+
}
139+
else
140+
{
141+
delete formValue.slug;
142+
}
143+
133144
if (tempLogo.value == null)
134145
{
135146
delete formValue.logo
@@ -183,6 +194,10 @@ const logoButtonText = computed(()=>{
183194
return logo.value !== null ? "Upload new" : "Upload Logo"
184195
})
185196
197+
const slug = computed(()=>{
198+
return form.value[0].slug ? form.value[0].slug : slugify (form.value[0].name ?? "", { lower: true, strict: true});
199+
})
200+
186201
</script>
187202
188203
<template>
@@ -230,6 +245,7 @@ const logoButtonText = computed(()=>{
230245
<StatusTag :value="form[0].status"/>
231246
232247
<InputField v-if="!companyExists" path="name" type="company" v-model="form[0].name"/>
248+
<InputField path="slug" type="company" v-model="slug" :disabled="true"/>
233249
<div class="row">
234250
<div class="col">
235251
<InputField path="tagline" type="company" v-model="form[0].tagline"/>

community-app/frontend/src/components/profile/Edu.vue

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script setup>
22
import { ref, watch, onMounted, computed } from 'vue'
3+
import slugify from 'slugify'
34
import Constants from '../../constants.js'
45
import FileUploader from './FileUploader.vue'
56
import SocialFields from './SocialFields.vue'
@@ -31,6 +32,7 @@ const emptyData = {
3132
enabled: false,
3233
logo: null,
3334
name: "",
35+
slug: "",
3436
description: "",
3537
status: 0,
3638
website: "",
@@ -76,7 +78,7 @@ const rules = {
7678
message: "Website is required",
7779
trigger: ['input', 'blur'],
7880
validator: (rule, value)=>{
79-
return form.value[0].social.website.length > 0;
81+
return form.value[0]?.social?.website?.length > 0;
8082
}
8183
},
8284
logo: {
@@ -118,6 +120,15 @@ const submit = async () => {
118120
delete formValue.status;
119121
delete formValue.website;
120122
123+
if (!form.value[0].slug)
124+
{
125+
formValue.slug = slug.value;
126+
}
127+
else
128+
{
129+
delete formValue.slug;
130+
}
131+
121132
if (tempLogo.value == null)
122133
{
123134
delete formValue.logo
@@ -171,6 +182,10 @@ const logoButtonText = computed(()=>{
171182
return logo.value !== null ? "Upload new" : "Upload Logo"
172183
})
173184
185+
const slug = computed(()=>{
186+
return form.value[0].slug ? form.value[0].slug : slugify (form.value[0].name ?? "", { lower: true, strict: true});
187+
})
188+
174189
</script>
175190
176191
<template>
@@ -218,6 +233,7 @@ const logoButtonText = computed(()=>{
218233
<StatusTag :value="form[0].status"/>
219234
220235
<InputField path="name" v-if="!eduExists" type="edu" v-model="form[0].name"/>
236+
<InputField path="slug" type="edu" v-model="slug" :disabled="true"/>
221237
222238
<FormItem path="description" type="edu">
223239
<template #content>

community-app/frontend/src/components/profile/HelpTexts.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,11 @@ const data = Object({
128128
placeholder: "My Institution"
129129
}
130130
},
131+
slug:{
132+
label: "Slug",
133+
help: "URL-safe version of a name or title, used in links.",
134+
placeholder: "Auto-generated"
135+
},
131136
tagline: {
132137
company: {
133138
label: "Tagline",

0 commit comments

Comments
 (0)