@vixoniccom/aqi 0.0.1-dev.5 → 0.0.1-dev.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build.zip CHANGED
Binary file
@@ -1,41 +1,23 @@
1
- import {
2
- Label,
3
- SelectAssetKna,
4
- SelectInput,
5
- TextFormat,
6
- TextInput,
7
- } from '@vixoniccom/modules'
1
+ import { Label, NumberInput, SelectAssetKna, TextFormat, TextInput } from '@vixoniccom/modules'
8
2
 
9
3
  export const appeareanceInputs = [
10
4
  new Label({ label: 'General' }),
11
- new TextInput({
12
- id: 'padding',
13
- label: 'Márgenes',
14
- required: false,
15
- description:
16
- 'CSS para mover la tarjeta. El formato es arriba/derecha/abajo/izquieda',
17
- }),
18
- new SelectAssetKna({
19
- id: 'backgroundImage',
20
- label: 'Fondo',
21
- required: false,
22
- extensions: ['jpg', 'png'],
23
- }),
5
+ new SelectAssetKna({ id: 'backgroundImage', label: 'Fondo', required: false, extensions: ['jpg', 'png'] }),
24
6
 
25
7
  new Label({ label: 'Diseño de la tarjeta' }),
26
- new TextInput({
27
- id: 'cardWidth',
28
- label: 'Ancho',
29
- required: false,
30
- description: 'Ancho de la tarjeta',
31
- }),
32
- new TextInput({
33
- id: 'cardHeight',
34
- label: 'Alto',
35
- required: false,
36
- description: 'Altura de la tarjeta',
37
- }),
38
- new TextInput({
8
+ new NumberInput({
9
+ id: 'topSeparationCard',
10
+ label: 'Separación desde arriba',
11
+ description: 'Separación de la tarjeta del margen superior',
12
+ }),
13
+ new NumberInput({
14
+ id: 'leftSeparationCard',
15
+ label: 'Separación desde izquierda',
16
+ description: 'Separación de la tarjeta del margen izquierdo',
17
+ }),
18
+ new NumberInput({ id: 'cardWidth', label: 'Ancho', required: false, description: 'Ancho de la tarjeta' }),
19
+ new NumberInput({ id: 'cardHeight', label: 'Alto', required: false, description: 'Altura de la tarjeta' }),
20
+ new NumberInput({
39
21
  id: 'cardGap',
40
22
  label: 'Separación entre elementos',
41
23
  required: false,
@@ -43,32 +25,16 @@ export const appeareanceInputs = [
43
25
  }),
44
26
 
45
27
  new Label({ label: 'Textos de la tarjeta' }),
46
- new TextFormat({
47
- id: 'aqiFormat',
48
- label: 'Formato del índice de calidad del aire',
49
- }),
50
- new TextFormat({
51
- id: 'stationFormat',
52
- label: 'Formato de estación que realizó la medición',
53
- }),
54
- new TextFormat({
55
- id: 'qualityFormat',
56
- label: 'Formato del mensaje sobre la calidad del aire',
57
- }),
28
+ new TextFormat({ id: 'aqiFormat', label: 'Formato del índice de calidad del aire' }),
29
+ new TextFormat({ id: 'stationFormat', label: 'Formato de estación que realizó la medición' }),
30
+ new TextFormat({ id: 'qualityFormat', label: 'Formato del mensaje sobre la calidad del aire' }),
58
31
 
59
32
  new Label({ label: 'Datos' }),
60
- new SelectInput({
61
- id: 'updateData',
62
- label: 'Frecuencia con la que se piden datos',
63
- items: [
64
- { label: '1 minuto', value: 1 },
65
- { label: '5 minutos', value: 5 },
66
- { label: '10 minutos', value: 10 },
67
- { label: '30 minutos', value: 30 },
68
- { label: '45 minutos', value: 45 },
69
- { label: '1 hora', value: 60 },
70
- ],
71
- defaultValue: 1,
33
+ new TextInput({
34
+ id: 'cityInput',
35
+ label: 'Ciudad a buscar',
36
+ description:
37
+ 'Ciudad de la que se quiere medir el aire. Para ver la ciudades disponibles se puede consultar aquí: https://aqicn.org/here',
72
38
  }),
73
39
  new TextInput({ id: 'msj0', label: 'Mensaje sin Datos' }),
74
40
  new TextFormat({ id: 'formatMjs', label: 'Formato Mensaje sin Datos' }),
@@ -9,13 +9,6 @@
9
9
  "type": "label",
10
10
  "label": "General"
11
11
  },
12
- {
13
- "id": "padding",
14
- "label": "Márgenes",
15
- "type": "text-input",
16
- "description": "CSS para mover la tarjeta. El formato es arriba/derecha/abajo/izquieda",
17
- "required": false
18
- },
19
12
  {
20
13
  "id": "backgroundImage",
21
14
  "label": "Fondo",
@@ -31,24 +24,36 @@
31
24
  "type": "label",
32
25
  "label": "Diseño de la tarjeta"
33
26
  },
27
+ {
28
+ "id": "topSeparationCard",
29
+ "label": "Separación desde arriba",
30
+ "type": "number-input",
31
+ "description": "Separación de la tarjeta del margen superior"
32
+ },
33
+ {
34
+ "id": "leftSeparationCard",
35
+ "label": "Separación desde izquierda",
36
+ "type": "number-input",
37
+ "description": "Separación de la tarjeta del margen izquierdo"
38
+ },
34
39
  {
35
40
  "id": "cardWidth",
36
41
  "label": "Ancho",
37
- "type": "text-input",
42
+ "type": "number-input",
38
43
  "description": "Ancho de la tarjeta",
39
44
  "required": false
40
45
  },
41
46
  {
42
47
  "id": "cardHeight",
43
48
  "label": "Alto",
44
- "type": "text-input",
49
+ "type": "number-input",
45
50
  "description": "Altura de la tarjeta",
46
51
  "required": false
47
52
  },
48
53
  {
49
54
  "id": "cardGap",
50
55
  "label": "Separación entre elementos",
51
- "type": "text-input",
56
+ "type": "number-input",
52
57
  "description": "Separación entre los elementos de la tarjeta",
53
58
  "required": false
54
59
  },
@@ -76,36 +81,10 @@
76
81
  "label": "Datos"
77
82
  },
78
83
  {
79
- "id": "updateData",
80
- "label": "Frecuencia con la que se piden datos",
81
- "type": "select-input",
82
- "items": [
83
- {
84
- "label": "1 minuto",
85
- "value": 1
86
- },
87
- {
88
- "label": "5 minutos",
89
- "value": 5
90
- },
91
- {
92
- "label": "10 minutos",
93
- "value": 10
94
- },
95
- {
96
- "label": "30 minutos",
97
- "value": 30
98
- },
99
- {
100
- "label": "45 minutos",
101
- "value": 45
102
- },
103
- {
104
- "label": "1 hora",
105
- "value": 60
106
- }
107
- ],
108
- "defaultValue": 1
84
+ "id": "cityInput",
85
+ "label": "Ciudad a buscar",
86
+ "type": "text-input",
87
+ "description": "Ciudad de la que se quiere medir el aire. Para ver la ciudades disponibles se puede consultar aquí: https://aqicn.org/here"
109
88
  },
110
89
  {
111
90
  "id": "msj0",
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "author": {
9
9
  "name": "Daniel Alvayay"
10
10
  },
11
- "version": "0.0.1-dev.5",
11
+ "version": "0.0.1-dev.7",
12
12
  "scripts": {
13
13
  "prepublishOnly": "vixonic-module-packager --mode=build",
14
14
  "watch": "vixonic-module-packager --mode=watch",
package/src/App.tsx CHANGED
@@ -4,7 +4,7 @@ import React, { useEffect, useState } from 'react'
4
4
  import { Card } from './components/Card'
5
5
  import { FontLoader } from './components/FontLoader'
6
6
  import { FormattedText } from './components/FormattedText'
7
- import { AirQuality, StorageData } from './types'
7
+ import { AirQuality, AqiData, StorageData } from './types'
8
8
  import { API_RESPONSE_STATUS, TOKEN } from './utils'
9
9
 
10
10
  interface Props {
@@ -15,8 +15,9 @@ interface Props {
15
15
  export const App: React.FunctionComponent<Props> = ({ data, start }) => {
16
16
  const { parameters, downloadsPath } = data
17
17
  const backgroundImageState = parameters.backgroundImage ? `url('${downloadsPath}/${parameters.backgroundImage.filename}')` : ''
18
- const [formattedData, setFormattedData] = useState<AirQuality | null>()
19
- const updateTime = (parameters?.updateData || 1) * 60000
18
+ const [formattedData, setFormattedData] = useState<AqiData>()
19
+ const cityInput = parameters?.cityInput || "santiago"
20
+ const updateTime = 600000
20
21
 
21
22
  const refetchData = (referenceDate: Date): boolean => {
22
23
  const now = new Date()
@@ -29,12 +30,11 @@ export const App: React.FunctionComponent<Props> = ({ data, start }) => {
29
30
  const differenceMinutes = Math.abs(now.getTime() - referenceDate.getTime())
30
31
  return differenceMinutes >= updateTime
31
32
  }
32
-
33
33
  return true
34
34
  }
35
35
 
36
36
  const requestData = async (): Promise<AirQuality | null> => {
37
- const URL = `https://api.waqi.info/feed/here/?token=${TOKEN}`
37
+ const URL = `https://api.waqi.info/feed/${cityInput}/?token=${TOKEN}`
38
38
  try {
39
39
  const response = await axios.get<AirQuality>(URL)
40
40
  if (response?.status === 200) {
@@ -42,21 +42,34 @@ export const App: React.FunctionComponent<Props> = ({ data, start }) => {
42
42
  }
43
43
  return null
44
44
  } catch (error) {
45
- console.log(error)
46
45
  return null
47
46
  }
48
47
  }
49
48
 
49
+ const processData = (response: AirQuality | null): AqiData => {
50
+ let data: AqiData = { city: cityInput, station: "Estación desconocida" }
51
+ if (response && response.status === API_RESPONSE_STATUS.OK) {
52
+ data = {
53
+ aqi: response.data.aqi,
54
+ city: cityInput,
55
+ station: response.data.city.name
56
+ }
57
+ }
58
+ return data
59
+ }
60
+
50
61
  const getData = async () => {
51
62
  const storageData: StorageData | null = await localforage.getItem('aqi')
52
63
  let data
53
- if (!storageData?.item || !storageData?.date || refetchData(new Date(storageData.date))) {
64
+ if (!storageData?.item || storageData?.item.city !== parameters.cityInput || !storageData?.date || refetchData(new Date(storageData.date))) {
54
65
  data = await requestData()
55
- await localforage.setItem('aqi', { item: data, date: new Date() })
66
+ const processedData = processData(data)
67
+ await localforage.setItem('aqi', { item: processedData, date: new Date() })
68
+ setFormattedData(processedData)
56
69
  } else {
57
70
  data = storageData.item
71
+ setFormattedData(data)
58
72
  }
59
- setFormattedData(data)
60
73
  }
61
74
 
62
75
  useEffect(() => {
@@ -66,48 +79,60 @@ export const App: React.FunctionComponent<Props> = ({ data, start }) => {
66
79
  getData()
67
80
  }, updateTime)
68
81
  return () => clearInterval(interval)
69
- }, [start, updateTime])
82
+ }, [start, updateTime, parameters.cityInput])
70
83
 
71
84
  return (
72
- <div
73
- style={{
74
- position: 'absolute',
75
- top: 0,
76
- bottom: 0,
77
- left: 0,
78
- right: 0,
79
- backgroundImage: backgroundImageState,
80
- backgroundSize: '100% 100%',
81
- padding: parameters?.padding
82
- }}
83
- >
84
- {formattedData?.status === API_RESPONSE_STATUS.OK ? (
85
- <div>
86
- <FontLoader paths={['aqiFormat.font', 'stationFormat.font', 'qualityFormat.font']} parameters={parameters} downloadsPath={downloadsPath} />
85
+ <div style={{
86
+ position: 'absolute',
87
+ top: 0,
88
+ bottom: 0,
89
+ left: 0,
90
+ right: 0,
91
+ display: "flex",
92
+ backgroundImage: backgroundImageState,
93
+ backgroundSize: '100% 100%',
94
+ }}>
95
+ <div style={{
96
+ width: "100%",
97
+ height: "100%",
98
+ position: "relative"
99
+ }}>
100
+ {formattedData ? (
101
+ <div style={{
102
+ position: "absolute",
103
+ top: `${parameters.topSeparationCard || 0}px`,
104
+ left: `${parameters.leftSeparationCard || 0}px`
105
+ }}>
106
+ <FontLoader paths={['aqiFormat.font', 'stationFormat.font', 'qualityFormat.font']} parameters={parameters} downloadsPath={downloadsPath} />
87
107
 
88
- <Card data={formattedData?.data}
89
- format={{
90
- cardWidth: parameters?.cardWidth,
91
- cardHeight: parameters?.cardHeight,
92
- cardGap: parameters?.cardGap,
93
- aqiFormat: parameters?.aqiFormat,
94
- stationFormat: parameters?.stationFormat,
95
- qualityFormat: parameters?.qualityFormat
96
- }} />
97
- </div>
98
- ) : (
99
- <div>
100
- <FontLoader paths={['formatMjs.font']} parameters={parameters} downloadsPath={downloadsPath} />
108
+ <Card data={formattedData}
109
+ format={{
110
+ cardWidth: parameters?.cardWidth,
111
+ cardHeight: parameters?.cardHeight,
112
+ cardGap: parameters?.cardGap,
113
+ aqiFormat: parameters?.aqiFormat,
114
+ stationFormat: parameters?.stationFormat,
115
+ qualityFormat: parameters?.qualityFormat
116
+ }} />
117
+ </div>
118
+ ) : (
101
119
  <div style={{
102
- display: 'flex',
103
- position: 'relative',
104
- flex: '1 1 0%',
105
- flexDirection: 'column',
120
+ position: "absolute",
121
+ top: `${parameters.topSeparationCard || 0}px`,
122
+ left: `${parameters.leftSeparationCard || 0}px`
106
123
  }}>
107
- <FormattedText text={parameters?.msj0 || 'No hay datos para mostrar'} format={parameters?.formatMjs} />
124
+ <FontLoader paths={['formatMjs.font']} parameters={parameters} downloadsPath={downloadsPath} />
125
+ <div style={{
126
+ display: 'flex',
127
+ position: 'relative',
128
+ flex: '1 1 0%',
129
+ flexDirection: 'column',
130
+ }}>
131
+ <FormattedText text={parameters?.msj0 || 'No hay datos para mostrar'} format={parameters?.formatMjs} />
132
+ </div>
108
133
  </div>
109
- </div>
110
- )}
134
+ )}
135
+ </div>
111
136
  </div>
112
137
  )
113
138
  }
@@ -1,15 +1,15 @@
1
- import React from 'react'
2
- import { assingAirQuality } from '../utils'
3
- import { Data } from '../types';
4
- import { TextFormat } from '@vixoniccom/modules'
5
- import { FormattedText } from './FormattedText'
1
+ import React from 'react';
2
+ import { assingAirQuality } from '../utils';
3
+ import { AqiData } from '../types';
4
+ import { TextFormat } from '@vixoniccom/modules';
5
+ import { FormattedText } from './FormattedText';
6
6
 
7
7
  interface Props {
8
- data: Data;
8
+ data: AqiData;
9
9
  format: {
10
- cardWidth?: string;
11
- cardHeight?: string;
12
- cardGap?: string;
10
+ cardWidth?: number;
11
+ cardHeight?: number;
12
+ cardGap?: number;
13
13
  aqiFormat?: TextFormat.Value;
14
14
  stationFormat?: TextFormat.Value;
15
15
  qualityFormat?: TextFormat.Value;
@@ -17,33 +17,35 @@ interface Props {
17
17
  }
18
18
 
19
19
  export const Card: React.FunctionComponent<Props> = ({ data, format }) => {
20
- const { color, quality } = assingAirQuality(data?.aqi)
20
+ const { color, quality } = assingAirQuality(data?.aqi || -1)
21
+ const city = data.station === "Estación desconocida" ? data.station : data.city
22
+
21
23
  return (
22
24
  <div style={{
23
25
  display: 'flex',
24
- width: format.cardWidth || 300,
25
- height: format.cardHeight || 200,
26
+ width: `${format.cardWidth || 300}px`,
27
+ height: `${format.cardHeight || 200}px`,
26
28
  flexDirection: 'column',
27
- padding: '1rem',
28
29
  backgroundColor: color,
29
- border: '2px solid #000',
30
- // gap: format.cardGap || '2rem',
30
+ borderRadius: "10px"
31
31
  }}>
32
- <div style={{
33
- textAlign: `${format.aqiFormat?.alignment?.horizontal || 'left'}`,
34
- padding: `${format.cardGap || '2rem'}`
35
- }}>
36
- <FormattedText text={String(data?.aqi)} format={format.aqiFormat} />
37
- </div>
32
+ {(data?.aqi) && (
33
+ <div style={{
34
+ textAlign: `${format.aqiFormat?.alignment?.horizontal || 'left'}`,
35
+ padding: `${format.cardGap || 2}rem`
36
+ }}>
37
+ <FormattedText text={String(data?.aqi)} format={format.aqiFormat} />
38
+ </div>
39
+ )}
38
40
  <div style={{
39
41
  textAlign: `${format.stationFormat?.alignment?.horizontal || 'left'}`,
40
- padding: `${format.cardGap || '2rem'}`,
42
+ padding: `${format.cardGap || 2}rem`,
41
43
  }}>
42
- <FormattedText text={String(`Estación: ${data?.city?.name}`)} format={format.stationFormat} />
44
+ <FormattedText text={city} format={format.stationFormat} />
43
45
  </div>
44
46
  <div style={{
45
47
  textAlign: `${format.qualityFormat?.alignment?.horizontal || 'left'}`,
46
- padding: `${format.cardGap || '2rem'}`,
48
+ padding: `${format.cardGap || 2}rem`,
47
49
  marginTop: '1rem'
48
50
  }}>
49
51
  <FormattedText text={data?.aqi ? quality : ''} format={format.qualityFormat} />
@@ -5,11 +5,12 @@ declare type VixonicData = {
5
5
  }
6
6
 
7
7
  declare type VixonicParameters = Partial<{
8
- padding: string
9
8
  backgroundImage: { id?: string; filename?: string; extension?: string }
10
- cardWidth: string
11
- cardHeight: string
12
- cardGap: string
9
+ topSeparationCard: number
10
+ leftSeparationCard: number
11
+ cardWidth: number
12
+ cardHeight: number
13
+ cardGap: number
13
14
  aqiFormat: {
14
15
  fontSize?: number
15
16
  fontColor?: string
@@ -28,7 +29,7 @@ declare type VixonicParameters = Partial<{
28
29
  alignment?: { horizontal?: 'left' | 'right' | 'center' }
29
30
  font?: { filename: string; id: string; __isAsset: true }
30
31
  }
31
- updateData: 1 | 5 | 10 | 30 | 45 | 60
32
+ cityInput: string
32
33
  msj0: string
33
34
  formatMjs: {
34
35
  fontSize?: number
@@ -1,14 +1,16 @@
1
1
  {
2
2
  "parameters": {
3
- "padding": "200px 100px 100px 600px",
4
3
  "backgroundImage": {
5
4
  "id": "earthquakes",
6
5
  "filename": "Earthquakes.png",
7
6
  "__isAsset": true
8
7
  },
9
- "cardWidth": "700px",
10
- "cardHeight": "600px",
11
- "cardGap": "2rem",
8
+ "cityInput": "Santiago",
9
+ "topSeparationCard": 200,
10
+ "leftSeparationCard": 600,
11
+ "cardWidth": 700,
12
+ "cardHeight": 600,
13
+ "cardGap": 2,
12
14
  "aqiFormat": {
13
15
  "fontSize": 18,
14
16
  "fontColor": "#000000",
@@ -31,4 +33,4 @@
31
33
  }
32
34
  }
33
35
  }
34
- }
36
+ }
package/src/types.d.ts CHANGED
@@ -1,14 +1,23 @@
1
+ export interface StorageData {
2
+ item: AqiData
3
+ date: Date
4
+ }
5
+
6
+ export interface AqiData {
7
+ city: string
8
+ aqi?: number
9
+ station: string
10
+ }
11
+
1
12
  export interface AirQuality {
2
- status: 'ok' | 'error' | number
13
+ status: Status
3
14
  data: Data
4
15
  }
5
16
 
6
- export interface StorageData {
7
- item: AirQuality
8
- date: Date
9
- }
17
+ type Status = 'ok' | 'error'
10
18
 
11
19
  export interface Data {
20
+ status?: Status
12
21
  aqi: number
13
22
  idx: number
14
23
  attributions: Attribution[]
package/src/utils.ts CHANGED
@@ -5,11 +5,9 @@ const API_RESPONSE_STATUS = {
5
5
  ERROR: 'error',
6
6
  }
7
7
 
8
- const assingAirQuality = (
9
- magnitude: number
10
- ): { color: string; quality: string } => {
11
- let color
12
- let quality
8
+ const assingAirQuality = (magnitude: number): { color: string; quality: string } => {
9
+ let color = '#9D9F93'
10
+ let quality = ''
13
11
  if (0 <= magnitude && magnitude <= 50) {
14
12
  color = '#009966'
15
13
  quality = 'Buena'
@@ -25,7 +23,7 @@ const assingAirQuality = (
25
23
  } else if (201 <= magnitude && magnitude <= 300) {
26
24
  color = '#660099'
27
25
  quality = 'Muy dañina a la salud'
28
- } else {
26
+ } else if (magnitude >= 301) {
29
27
  color = '#7E0023'
30
28
  quality = 'Arriesgado'
31
29
  }