generated from xqsit94/vite-vue3-ts-starter
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fetch random integers and display chart bars
- Loading branch information
Showing
22 changed files
with
365 additions
and
96 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
interface ImportMeta { | ||
readonly env: ImportMetaEnv; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<template> | ||
<button class="button" type="button"> | ||
<slot/> | ||
</button> | ||
</template> | ||
|
||
<style scoped lang="css"> | ||
.button { | ||
border-radius: 16px; | ||
border: none; | ||
padding: 20px 24px; | ||
font-weight: bold; | ||
background-color: indigo; | ||
color: floralwhite; | ||
cursor: pointer; | ||
&:hover { | ||
opacity: 0.8; | ||
} | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
<script setup lang="ts"> | ||
defineProps<{ | ||
recordValues: Record<string | number, number> | ||
}>() | ||
const getBarHeight = (value: number) => `${value * 10}px` | ||
</script> | ||
|
||
<template> | ||
<div class="chart"> | ||
<div | ||
v-for="(occurrences, label) in recordValues" | ||
:key="`${label}-${occurrences}`" | ||
class="bar" | ||
:style="{ height: `${getBarHeight(occurrences)}` }" | ||
data-testid="chart-bar" | ||
> | ||
<span class="label" data-testid="chart-bar-label">{{ label }}</span> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<style scoped lang="css"> | ||
.chart { | ||
display: flex; | ||
min-height: 200px; | ||
gap: 16px; | ||
} | ||
.bar { | ||
position: relative; | ||
background-color: cornflowerblue; | ||
border: indigo; | ||
width: 40px; | ||
text-align: center; | ||
border-radius: 4px; | ||
color: indigo; | ||
margin-top: auto; | ||
} | ||
.label { | ||
position: absolute; | ||
bottom: -20px; | ||
left: 50%; | ||
transform: translateX(-50%); | ||
} | ||
</style> |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { POST } from '@/utils/http' | ||
|
||
export type SearchRandomIntegersParams = { | ||
base: 2 | 8 | 10 | 16 | ||
col: number | ||
format: 'plain' | 'html' | ||
max: number | ||
min: number | ||
num: number | ||
} | ||
export const searchRandomIntegers = async (params: SearchRandomIntegersParams): Promise<string[]> => { | ||
const { num, min, max, col, base, format } = params | ||
|
||
return await POST( | ||
`/integers/?num=${num}&min=${min}&max=${max}&col=${col}&base=${base}&format=${format}`, | ||
null | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<template> | ||
<div class="page-layout"> | ||
<slot/> | ||
</div> | ||
</template> | ||
|
||
<style scoped lang="css"> | ||
.page-layout { | ||
display: flex; | ||
flex-direction: column; | ||
justify-content: center; | ||
align-items: center; | ||
gap: 20px; | ||
height: 100vh; | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,35 @@ | ||
<script setup lang="ts"> | ||
import CounterCard from '@/components/counter-card.vue' | ||
import Button from '@/components/button.vue' | ||
import Chart from '@/components/chart.vue' | ||
import PageLayout from '@/layouts/page-layout.vue' | ||
import { useRandomIntegersStore } from '@/stores/useRandomIntegers.store.ts' | ||
import { storeToRefs } from 'pinia' | ||
const { integersArray } = storeToRefs(useRandomIntegersStore()) | ||
const { searchIntegers } = useRandomIntegersStore() | ||
const handleSearchButtonClick = () => { | ||
searchIntegers({ num: 20, min: 1, max: 10, col: 1, base: 2, format: 'plain' }) | ||
} | ||
</script> | ||
|
||
<template> | ||
<div class="h-screen flex flex-col justify-center items-center gap-5"> | ||
<CounterCard msg="Vite + Vue + TS" /> | ||
</div> | ||
<PageLayout> | ||
<h1>{{ 'Distribution de nombres' }}</h1> | ||
|
||
<div class="content-wrapper"> | ||
<Chart :recordValues="integersArray" /> | ||
<Button @click="handleSearchButtonClick"> Refresh </Button> | ||
</div> | ||
</PageLayout> | ||
</template> | ||
|
||
<style lang="css" scoped> | ||
.content-wrapper { | ||
display: flex; | ||
flex-direction: column; | ||
align-items: center; | ||
justify-content: center; | ||
gap: 32px; | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { | ||
searchRandomIntegers, | ||
SearchRandomIntegersParams | ||
} from '@/features/integersList/searchRandomIntegers.ts' | ||
import { ref } from 'vue' | ||
import { defineStore } from 'pinia' | ||
export const useRandomIntegersStore = defineStore('integersList', () => { | ||
const integersArray = ref<Record<number, number>>([]) | ||
|
||
const searchIntegers = async (params: SearchRandomIntegersParams) => { | ||
integersArray.value = groupIntegersByValue(await searchRandomIntegers(params)) | ||
} | ||
|
||
const groupIntegersByValue = (integersArray: string[]) => { | ||
const occurrences: Record<string, number> = {}; | ||
|
||
integersArray.forEach((integer) => { | ||
occurrences[integer] = (occurrences[integer] || 0) + 1; | ||
}); | ||
|
||
return occurrences; | ||
} | ||
|
||
return { integersArray, searchIntegers } | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export const httpClient = async (input: RequestInfo, init?: RequestInit): Promise<Response> => { | ||
const response = await fetch(input, init) | ||
if (!response.ok) { | ||
throw new Error(`[${response.status}] ${response.statusText}`) | ||
} | ||
return response | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { POST } from './post.ts' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { httpClient } from '@/utils/http/httpClient.ts' | ||
export const POST = async (endpoint: string, body?: unknown): Promise<string[]> => { | ||
const url = `${import.meta.env.VITE_API}${endpoint}` | ||
const response = await httpClient(url, { | ||
method: 'Post', | ||
body: JSON.stringify(body) || null, | ||
headers: { | ||
Accept: 'application/json', | ||
'Content-Type': 'application/json' | ||
} | ||
}) | ||
const contentType = response.headers.get('Content-Type') | ||
|
||
if (contentType === 'text/plain;charset=UTF-8') { | ||
if (!response.body) { | ||
return [] | ||
} | ||
|
||
return decodeReadableStream(response.body) | ||
} | ||
|
||
/* if (contentType === 'application/json') return response.json() */ | ||
|
||
throw new Error('Type de contenu non pris en charge') | ||
} | ||
|
||
const decodeReadableStream = async (readableStream: ReadableStream): Promise<string[]> => { | ||
const reader = readableStream.getReader() | ||
const chunks: Uint8Array[] = [] | ||
|
||
let isDone = false | ||
|
||
while (!isDone) { | ||
const { done, value } = await reader.read() | ||
|
||
if (done) { | ||
isDone = true | ||
} | ||
|
||
if (value) { | ||
chunks.push(value) | ||
} | ||
} | ||
|
||
reader.releaseLock() | ||
|
||
return decodeChunksToStringArray(chunks) | ||
} | ||
|
||
const decodeChunksToStringArray = (chunks: Uint8Array[]): string[] => { | ||
return ( | ||
chunks.reduce( | ||
(acc: string[], chunk: Uint8Array) => | ||
acc.concat(new TextDecoder().decode(chunk.buffer).split('\n').slice(0, -1)), | ||
[] | ||
) || [] | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import Button from '@/components/button.vue' | ||
import { describe, it, expect, beforeEach } from 'vitest' | ||
|
||
import { shallowMount, VueWrapper } from '@vue/test-utils' | ||
|
||
describe('Button', () => { | ||
let wrapper: VueWrapper | ||
beforeEach(() => { | ||
wrapper = shallowMount(Button, { | ||
props: { | ||
recordValues: { 20: 2, 15: 1 } | ||
} | ||
}) | ||
}) | ||
|
||
it('should render properly', () => { | ||
expect(wrapper.exists()).toBe(true) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import Chart from '@/components/chart.vue' | ||
import { describe, it, expect, beforeEach } from 'vitest' | ||
|
||
import { shallowMount, VueWrapper } from '@vue/test-utils' | ||
|
||
describe('Chart', () => { | ||
let wrapper: VueWrapper | ||
beforeEach(() => { | ||
wrapper = shallowMount(Chart, { | ||
props: { | ||
recordValues: { 20: 2, 15: 1 } | ||
} | ||
}) | ||
}) | ||
|
||
it('should render properly', () => { | ||
expect(wrapper.exists()).toBe(true) | ||
}) | ||
|
||
it('should render 2 bars given occurences of numbers', () => { | ||
expect(wrapper.findAll('[data-testid="chart-bar"]').length).toBe(2) | ||
}) | ||
|
||
it('should render the right label given occurrences of numbers', () => { | ||
const [first, second] = wrapper.findAll('[data-testid="chart-bar-label"]') | ||
|
||
expect(first.text()).toBe('15') | ||
expect(second.text()).toBe('20') | ||
}) | ||
|
||
it('should render 10 bars given occurences of numbers', async () => { | ||
await wrapper.setProps({ | ||
recordValues: { 20: 2, 15: 1, 56: 5, 18: 6, 63: 1, 57: 7, 68: 8, 96: 5, 656: 5, 66: 6 } | ||
}) | ||
|
||
expect(wrapper.findAll('[data-testid="chart-bar"]').length).toBe(10) | ||
}) | ||
|
||
it('should render 2 bars given occurences of text', async () => { | ||
await wrapper.setProps({ recordValues: { '20': 2, '15': 1 } }) | ||
|
||
expect(wrapper.findAll('[data-testid="chart-bar"]').length).toBe(2) | ||
}) | ||
|
||
it('should render the right label given occurrences of text', async () => { | ||
await wrapper.setProps({ recordValues: { '20': 2, '15': 1 } }) | ||
const [first, second] = wrapper.findAll('[data-testid="chart-bar-label"]') | ||
|
||
expect(first.text()).toBe('15') | ||
expect(second.text()).toBe('20') | ||
}) | ||
}) |
Oops, something went wrong.