Skip to content

Commit

Permalink
More migrations to TypeScript and composables.
Browse files Browse the repository at this point in the history
Refs #156
  • Loading branch information
The4thLaw committed Sep 25, 2024
1 parent 6ad07b6 commit eaffb55
Show file tree
Hide file tree
Showing 34 changed files with 363 additions and 479 deletions.
4 changes: 2 additions & 2 deletions source/demyo-vue-frontend/src/components/TextIndex.vue
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ import { focusElement } from '@/helpers/dom'
import { useTemplateRef } from 'vue'
interface Props {
items?: AbstractModel[]
items?: IModel[]
splitByFirstLetter?: boolean,
firstLetterExtractor: (item: AbstractModel) => string,
firstLetterExtractor?: (item: AbstractModel) => string,
compact?: boolean
}
const props = withDefaults(defineProps<Props>(), {
Expand Down
4 changes: 2 additions & 2 deletions source/demyo-vue-frontend/src/composables/model-index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import { useI18n } from 'vue-i18n'
* @param serviceInstance The service to use to fetch the data.
* @param titleKey the page title key
*/
export function useSimpleIndex<T extends IModel>(serviceInstance: AbstractModelService, titleKey: string,
fetchData: (() => Promise<T[]>) | null = null) {
export function useSimpleIndex<T extends IModel>(serviceInstance: AbstractModelService<T>, titleKey: string,
fetchData?: (() => Promise<T[]>)) {
//
let safeFetchData: () => Promise<T[]>
safeFetchData = fetchData || (() => serviceInstance.findForIndex())
Expand Down
4 changes: 2 additions & 2 deletions source/demyo-vue-frontend/src/composables/model-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ interface ViewData<T extends AbstractModel> {
}

export function useSimpleView<T extends AbstractModel>(fetchData: (id: number) => Promise<T>,
service: AbstractModelService, confirmDeleteLabel: string, indexRouteName: string,
service: AbstractModelService<T>, confirmDeleteLabel: string, indexRouteName: string,
titleProvider = (model: T) => model.identifyingName): ViewData<T> {
//
const route = useRoute()
const i18n = useI18n()
const router = useRouter()
const uiStore = useUiStore()

const parsedId = ref(null) as Ref<number | null>
const parsedId = ref(undefined) as Ref<number | undefined>
const loading = ref(false)
const model = ref({}) as Ref<T>
const appTasksMenu = ref(false)
Expand Down
4 changes: 2 additions & 2 deletions source/demyo-vue-frontend/src/composables/pagination.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ interface PaginationState<T extends AbstractModel> {
nextPage: () => void
}

export function useBasicPagination<T extends AbstractModel>(items: Ref<T[]>, itemsPerPage: Ref<number> | null = null): PaginationState<T> {
export function useBasicPagination<T extends AbstractModel>(items: Ref<T[]>, itemsPerPage?: Ref<number>): PaginationState<T> {
return usePagination(items, () => '#', () => {}, itemsPerPage)
}

export function usePagination<T extends AbstractModel>(items: Ref<T[]>, firstLetterExtractor: (item: T) => string,
emit: (evt: string) => void, itemsPerPage: Ref<number> | null): PaginationState<T> {
emit: (evt: string) => void, itemsPerPage?: Ref<number>): PaginationState<T> {
const currentPage = ref(1)

const readerStore = useReaderStore()
Expand Down
6 changes: 3 additions & 3 deletions source/demyo-vue-frontend/src/composables/quicksearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ export function useQuicksearch() {
const currentQuery = ref('')
const lastQuery = ref('')
const loading = ref(false)
const results = ref<IModel[] | null>(null)
const results = ref<IModel[] | undefined>(undefined)

const isRelevantSearchQuery = computed(() => currentQuery.value && currentQuery.value.length)

function clearSearch() {
currentQuery.value = ''
lastQuery.value = ''
results.value = null
results.value = undefined
}

function performSearch() {
Expand All @@ -21,7 +21,7 @@ export function useQuicksearch() {
return
}
lastQuery.value = currentQuery.value
results.value = null
results.value = undefined
debouncedSearch()
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,43 +1,49 @@
import axios from 'axios'
import { apiRoot } from '@/myenv'
import axios from 'axios'

function baselineUrl(url) {
function baselineUrl(url: string) {
return apiRoot + url
}

export async function axiosGet(url, data, defaultValue) {
export async function axiosGet<T>(url: string, data: T|any|undefined = undefined, defaultValue: T|undefined = undefined): Promise<T> {
let def: T
if (defaultValue === undefined) {
defaultValue = data
def = data
data = {}
} else {
def = defaultValue
}

let response
try {
response = await axios.get(baselineUrl(url), { params: data })
} catch (e) {
console.warn(`Failed to get the resource at ${url}`, e)
return defaultValue
return def
}
return response.data
}

export async function axiosPost(url, data, defaultValue) {
export async function axiosPost<T>(url: string, data: T|any, defaultValue: T|undefined = undefined): Promise<T> {
let def: T
if (defaultValue === undefined) {
defaultValue = data
def = data
data = {}
} else {
def = defaultValue
}

let response
try {
response = await axios.post(baselineUrl(url), data)
} catch (e) {
console.warn(`Failed to post the data at ${url}`, data, e)
return defaultValue
return def
}
return response.data
}

export async function axiosPut(url, data, defaultValue) {
export async function axiosPut<T>(url: string, data: any, defaultValue: T): Promise<T> {
let response
try {
response = await axios.put(baselineUrl(url), data)
Expand All @@ -48,13 +54,13 @@ export async function axiosPut(url, data, defaultValue) {
return response.data
}

export async function axiosDelete(url, defaultValue) {
export async function axiosDelete<T>(url: string, defaultValue: T): Promise<T> {
let response
try {
response = await axios.delete(baselineUrl(url))
} catch (e) {
console.warn(`Failed to delete the resource at ${url}`, e)
return defaultValue
return Promise.resolve(defaultValue)
}
return response.data
}
4 changes: 2 additions & 2 deletions source/demyo-vue-frontend/src/layouts/DefaultLayout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ const showQuicksearch = ref(false)
const promptReaderSelection = ref(false)
const menuItems = ref(defaultMenu)
let pageTitleObserver: MutationObserver | null;
let pageTitleObserver: MutationObserver | undefined;
onMounted(() => {
// Monitor the page title for changes
pageTitleObserver = new MutationObserver((mutations) => {
Expand All @@ -167,7 +167,7 @@ onMounted(() => {
})
onUnmounted(() => {
pageTitleObserver?.disconnect()
pageTitleObserver = null
pageTitleObserver = undefined
})
const uiStore = useUiStore()
Expand Down
2 changes: 1 addition & 1 deletion source/demyo-vue-frontend/src/pages/albums/AlbumIndex.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { useRoute } from 'vue-router'
const route = useRoute()
function fetchData() {
const filter = retrieveFilter(route)
const filter = retrieveFilter(route) as AlbumFilter
return albumService.findForIndex(filter)
}
Expand Down
2 changes: 1 addition & 1 deletion source/demyo-vue-frontend/src/pages/albums/AlbumView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ import { useTemplateRef } from 'vue'
import { useI18n } from 'vue-i18n'
const dndDialog = ref(false)
const derivativeCount = ref(0)
const derivativeCount = ref(-1)
const inhibitObserver = ref(true)
const derivativesLoading = ref(false)
const derivatives = ref([] as Derivative[])
Expand Down
159 changes: 63 additions & 96 deletions source/demyo-vue-frontend/src/pages/authors/AuthorView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
:confirm="$t('quickTasks.delete.author.confirm')"
icon="mdi-account dem-overlay-delete"
@cancel="appTasksMenu = false"
@confirm="deleteAuthor"
@confirm="deleteModel"
/>
</AppTasks>

<SectionCard :loading="mainLoading" :image="author.portrait" :title="author.identifyingName">
<SectionCard :loading="authorLoading" :image="author.portrait" :title="author.identifyingName">
<FieldValue v-if="author.website" :label="$t('field.Author.website')">
<a :href="author.website">{{ author.website }}</a>
</FieldValue>
Expand All @@ -37,14 +37,14 @@
{{ $t('page.Author.noAlbums') }}
</v-alert>
<v-btn
v-if="count > 0"
v-if="derivativeCount > 0"
:to="{ name: 'DerivativeIndex', query: { withArtist: author.id } }"
color="secondary" class="my-4" size="small" variant="outlined"
>
{{ $t('page.Author.viewDerivatives', count) }}
{{ $t('page.Author.viewDerivatives', derivativeCount) }}
</v-btn>
<v-alert
v-if="count === 0"
v-if="derivativeCount === 0"
border="start" type="info" text class="my-4"
>
{{ $t('page.Author.noDerivatives') }}
Expand All @@ -65,106 +65,73 @@
</v-container>
</template>

<script>
import { deleteStub } from '@/helpers/actions'
import modelViewMixin from '@/mixins/model-view'
<script setup lang="ts">
import { useSimpleView } from '@/composables/model-view'
import authorService from '@/services/author-service'
import dayjs from 'dayjs'
import { useI18n } from 'vue-i18n'
export default {
name: 'AuthorView',
const authorLoading = ref(true)
const albumsLoading = ref(true)
const authorAlbums = ref({} as AuthorAlbums)
const derivativeCount = ref(-1)
mixins: [modelViewMixin],
async function fetchData(id: number): Promise<Author> {
authorLoading.value = true
albumsLoading.value = true
data() {
return {
mainLoading: true,
albumsLoading: true,
author: {},
authorAlbums: {},
count: -1,
appTasksMenu: false
}
},
const derivCountP = authorService.countDerivatives(id)
const authorP = await authorService.findById(id)
authorLoading.value = false
head() {
return {
title: this.author.identifyingName
}
},
const loadedAuthorAlbums = await authorService.getAuthorAlbums(id)
authorAlbums.value = JSON.parse(JSON.stringify(loadedAuthorAlbums))
albumsLoading.value = false
computed: {
albums() {
return this.authorAlbums.albums || []
},
derivativeCount.value = await derivCountP
albumCount() {
return this.albums.length
},
works() {
return {
asArtist: new Set(this.authorAlbums.asArtist),
asWriter: new Set(this.authorAlbums.asWriter),
asColorist: new Set(this.authorAlbums.asColorist),
asInker: new Set(this.authorAlbums.asInker),
asTranslator: new Set(this.authorAlbums.asTranslator)
}
},
isAlive() {
return this.author.birthDate && !this.author.deathDate
},
age() {
if (!this.author.birthDate) {
return null
}
const endDate = this.author.deathDate ? dayjs(this.author.deathDate) : dayjs()
return endDate.diff(this.author.birthDate, 'year')
}
},
methods: {
async fetchData() {
this.mainLoading = true
const countP = authorService.countDerivatives(this.parsedId)
this.author = await authorService.findById(this.parsedId)
this.mainLoading = false
const authorAlbums = await authorService.getAuthorAlbums(this.parsedId)
this.authorAlbums = ref(JSON.parse(JSON.stringify(authorAlbums)))
this.albumsLoading = false
this.count = await countP
},
describeAuthor(albumId) {
const qualifiers = []
if (this.works.asArtist.has(albumId)) {
qualifiers.push(this.$t('page.Author.works.role.artist'))
}
if (this.works.asWriter.has(albumId)) {
qualifiers.push(this.$t('page.Author.works.role.writer'))
}
if (this.works.asColorist.has(albumId)) {
qualifiers.push(this.$t('page.Author.works.role.colorist'))
}
if (this.works.asInker.has(albumId)) {
qualifiers.push(this.$t('page.Author.works.role.inker'))
}
if (this.works.asTranslator.has(albumId)) {
qualifiers.push(this.$t('page.Author.works.role.translator'))
}
return qualifiers.join(', ')
},
return authorP
}
deleteAuthor() {
deleteStub(this,
() => authorService.deleteModel(this.author.id),
'quickTasks.delete.author.confirm.done',
'AuthorIndex')
}
const {model: author, loading, appTasksMenu, deleteModel} = useSimpleView(fetchData, authorService,
'quickTasks.delete.author.confirm.done', 'AuthorIndex')
const albums = computed(() => authorAlbums.value.albums || [])
const albumCount = computed(() => albums.value.length)
const works = computed(() => ({
asArtist: new Set(authorAlbums.value.asArtist),
asWriter: new Set(authorAlbums.value.asWriter),
asColorist: new Set(authorAlbums.value.asColorist),
asInker: new Set(authorAlbums.value.asInker),
asTranslator: new Set(authorAlbums.value.asTranslator)
}))
const isAlive = computed(() => author.value.birthDate && !author.value.deathDate)
const age = computed(() => {
if (!author.value.birthDate) {
return null
}
const endDate = author.value.deathDate ? dayjs(author.value.deathDate) : dayjs()
return endDate.diff(author.value.birthDate, 'year')
})
const i18n = useI18n()
function describeAuthor(albumId: number): string {
const qualifiers = []
if (works.value.asArtist.has(albumId)) {
qualifiers.push(i18n.t('page.Author.works.role.artist'))
}
if (works.value.asWriter.has(albumId)) {
qualifiers.push(i18n.t('page.Author.works.role.writer'))
}
if (works.value.asColorist.has(albumId)) {
qualifiers.push(i18n.t('page.Author.works.role.colorist'))
}
if (works.value.asInker.has(albumId)) {
qualifiers.push(i18n.t('page.Author.works.role.inker'))
}
if (works.value.asTranslator.has(albumId)) {
qualifiers.push(i18n.t('page.Author.works.role.translator'))
}
return qualifiers.join(', ')
}
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
import { useSimpleView } from '@/composables/model-view'
import bindingService from '@/services/binding-service'
const albumCount = ref(0)
const albumCount = ref(-1)
async function fetchData(id: number): Promise<Binding> {
const bindingP = bindingService.findById(id)
Expand Down
Loading

0 comments on commit eaffb55

Please sign in to comment.