Skip to content
Merged
23 changes: 4 additions & 19 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
},
"dependencies": {
"@disfactory/exif-js": "^2.3.0",
"@vue/composition-api": "^0.3.2",
"axios": "^0.19.0",
"copy-to-clipboard": "^3.3.1",
"core-js": "^3.4.2",
Expand Down
44 changes: 15 additions & 29 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,9 @@
<safety-modal v-model="modalState.safetyModalOpen" />
<tutorial-modal :open="modalState.tutorialModalOpen" :dismiss="modalActions.closeTutorialModal" />
<ios-version-modal :open="modalState.supportIOSVersionModalOpen" :dismiss="modalActions.closesupportIOSVersionModal" />
<api-config-modal :open="modalState.apiConfigModalOpen" :dismiss="modalActions.closeApiConfigModal" />
<!-- alert or modal -->
<Map
<MapView
:setFactoryLocation="appActions.setFactoryLocation"
/>

Expand All @@ -136,12 +137,9 @@
</template>

<script lang="ts">
import { createComponent, ref, provide } from '@vue/composition-api'
import { defineComponent, ref, provide } from 'vue'

import Map from '@/components/Map.vue'
import AppNavbar from '@/components/AppNavbar.vue'
import AppButton from '@/components/AppButton.vue'
import AppSidebar from './components/AppSidebar.vue'
import MapView from '@/components/Map.vue'
import AppAlert from '@/components/AppAlert.vue'
import CreateFactorySteps from '@/components/CreateFactorySteps.vue'
import UpdateFactorySteps from '@/components/UpdateFactorySteps.vue'
Expand All @@ -152,52 +150,40 @@ import ContactModal from '@/components/ContactModal.vue'
import GettingStartedModal from '@/components/GettingStartedModal.vue'
import TutorialModal from '@/components/TutorialModal.vue'
import SafetyModal from '@/components/SafetyModal.vue'
import CreateFactorySuccessModal from '@/components/CreateFactorySuccessModal.vue'
import UpdateFactorySuccessModal from '@/components/UpdateFactorySuccessModal.vue'
import IosVersionModal from '@/components/IOSVersionAlertModal.vue'
import ApiConfigModal from '@/components/ApiConfigModal.vue'

import { MapFactoryController } from './lib/map'
import { MainMapControllerSymbol } from './symbols'
import { provideModalState, useModalState } from './lib/hooks'
import { provideGA } from './lib/useGA'
import { provideAppState, useAppState } from './lib/appState'
import { provideAlertState, useAlertState } from './lib/useAlert'
import { provideMapMode } from './lib/useMapMode'
import { useModalState } from './lib/hooks'
import { useAppState } from './lib/appState'
import { useAlertState } from './lib/useAlert'

export default createComponent({
export default defineComponent({
name: 'App',
components: {
Map,
MapView,
AppAlert,
AppButton,
AppNavbar,
AppSidebar,
AboutModal,
ContactModal,
GettingStartedModal,
SafetyModal,
CreateFactorySuccessModal,
UpdateFactorySuccessModal,
TutorialModal,
IosVersionModal,
ApiConfigModal,
CreateFactorySteps,
UpdateFactorySteps,
FactoryDetailPage
},
setup (_, context) {
provideGA(context)

provideModalState()
provideAppState()
provideAlertState()
provideMapMode()

setup () {
const [modalState, modalActions] = useModalState()
const [appState, appActions] = useAppState()
const [alertState, alertActions] = useAlertState()

// register global accessible map instance
provide(MainMapControllerSymbol, ref<MapFactoryController>(null))
provide(MainMapControllerSymbol, ref<MapFactoryController | null>(null))

// Note: API config modal functionality removed for simplification

const drawer = ref(false)
return {
Expand Down
14 changes: 11 additions & 3 deletions src/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
import axios from 'axios'
import { FactoryPostData, FactoryData, FactoriesResponse, FactoryImage, ReportRecord } from '@/types'
import EXIF from '@disfactory/exif-js'

const baseURL = process.env.NODE_ENV === 'production' ? process.env.VUE_APP_BASE_URL : '/server/api'
import { currentBaseURL } from '@/lib/apiConfig'
import { watch } from 'vue'

const instance = axios.create({
baseURL,
headers: {
'Content-Type': 'application/json'
}
})

// Update base URL whenever currentBaseURL changes
const updateBaseURL = () => {
instance.defaults.baseURL = currentBaseURL.value

Check warning on line 15 in src/api/index.ts

View workflow job for this annotation

GitHub Actions / lint

Unsafe assignment of an `any` value
}

// Set initial base URL and watch for changes
updateBaseURL()
watch(currentBaseURL, updateBaseURL)

type ImageResponse = {
token: string
}
Expand All @@ -22,8 +30,8 @@

export async function getFactories (range: number, lng: number, lat: number): Promise<FactoriesResponse> {
try {
const { data } = await instance.get(`/factories?range=${range}&lng=${lng}&lat=${lat}`)

Check warning on line 33 in src/api/index.ts

View workflow job for this annotation

GitHub Actions / lint

Unsafe array destructuring of a tuple element with an `any` value
return data

Check warning on line 34 in src/api/index.ts

View workflow job for this annotation

GitHub Actions / lint

Unsafe return of an `any` typed value
} catch (err) {
console.error(err)
throw new TypeError('Get factory failed')
Expand All @@ -32,8 +40,8 @@

export async function getFactory (factoryId: string): Promise<FactoryData> {
try {
const { data } = await instance.get(`/factories/${factoryId}`)

Check warning on line 43 in src/api/index.ts

View workflow job for this annotation

GitHub Actions / lint

Unsafe array destructuring of a tuple element with an `any` value
return data

Check warning on line 44 in src/api/index.ts

View workflow job for this annotation

GitHub Actions / lint

Unsafe return of an `any` typed value
} catch (err) {
console.error(err)
throw new TypeError('Get factory failed')
Expand All @@ -46,7 +54,7 @@
const formData = new FormData()
formData.append('image', file)

const { data } = await axios({

Check warning on line 57 in src/api/index.ts

View workflow job for this annotation

GitHub Actions / lint

Unsafe array destructuring of a tuple element with an `any` value
method: 'POST',
url: 'https://api.imgur.com/3/image',
data: formData,
Expand All @@ -57,8 +65,8 @@
})

return {
link: data.data.link as string,

Check warning on line 68 in src/api/index.ts

View workflow job for this annotation

GitHub Actions / lint

Unsafe member access .data on an `any` value
deletehash: data.data.deletehash as string,

Check warning on line 69 in src/api/index.ts

View workflow job for this annotation

GitHub Actions / lint

Unsafe member access .data on an `any` value
file
}
}
Expand All @@ -76,7 +84,7 @@
resolve({})
return
}
const data: ExifData = EXIF.readFromBinaryFile(e.target.result)

Check warning on line 87 in src/api/index.ts

View workflow job for this annotation

GitHub Actions / lint

Unsafe assignment of an `any` value

const result: AfterExifData = {}
if (data.GPSLatitude) {
Expand Down
4 changes: 2 additions & 2 deletions src/components/AboutModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@

<script lang="ts">
import AppModal from '@/components/AppModal.vue'
import { createComponent } from '@vue/composition-api'
import { defineComponent } from 'vue'

export default createComponent({
export default defineComponent({
name: 'AboutModal',
components: {
AppModal
Expand Down
185 changes: 185 additions & 0 deletions src/components/ApiConfigModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
<template>
<div class="api-config-modal-container">
<app-modal :open="open" :dismiss="dismiss">
<div class="page">
<h2>API 設定</h2>

<div class="form-section">
<label for="api-url-input">API 基礎網址</label>
<input
id="api-url-input"
v-model="apiUrl"
type="text"
:placeholder="defaultUrl"
class="url-input"
data-testid="api-url-input"
/>
<small class="help-text">
留空將使用預設值:{{ defaultUrl }}
</small>
</div>

<div class="button-section">
<app-button @click="saveConfiguration" data-testid="save-button">
儲存設定
</app-button>
<app-button
@click="resetToDefault"
:outline="true"
data-testid="reset-button"
>
重置為預設值
</app-button>
</div>

<div class="current-config">
<strong>目前使用的 API 網址:</strong>
<span class="current-url">{{ currentUrl }}</span>
</div>
</div>
</app-modal>
</div>
</template>

<script lang="ts">
import AppModal from '@/components/AppModal.vue'
import AppButton from '@/components/AppButton.vue'
import { defineComponent, ref, computed } from 'vue'
import {
getDefaultBaseURL,
getCustomBaseURL,
setCustomBaseURL,
resetToDefaultBaseURL,
currentBaseURL
} from '@/lib/apiConfig'

export default defineComponent({
name: 'ApiConfigModal',
components: {
AppModal,
AppButton
},
props: {
open: {
type: Boolean,
default: false
},
dismiss: {
type: Function
}
},
setup (props) {
const apiUrl = ref(getCustomBaseURL() || '')
const defaultUrl = getDefaultBaseURL()
const currentUrl = computed(() => currentBaseURL.value)

Check warning on line 74 in src/components/ApiConfigModal.vue

View workflow job for this annotation

GitHub Actions / lint

Unsafe return of an `any` typed value

const saveConfiguration = () => {
const url = apiUrl.value.trim()
if (url) {
setCustomBaseURL(url)
} else {
resetToDefaultBaseURL()
}

if (props.dismiss) {
props.dismiss()
}
}

const resetToDefault = () => {
apiUrl.value = ''
resetToDefaultBaseURL()

if (props.dismiss) {
props.dismiss()
}
}

return {
apiUrl,
defaultUrl,
currentUrl,
saveConfiguration,
resetToDefault
}
}
})
</script>

<style lang="scss" scoped>
@import '@/styles/variables';
@import '@/styles/page';

.api-config-modal-container .app-modal {
max-width: 500px;
width: 90%;

.page {
h2 {
color: $primary-color;
margin-bottom: 20px;
text-align: center;
}

.form-section {
margin-bottom: 20px;

label {
display: block;
margin-bottom: 8px;
font-weight: bold;
color: $font-color;
}

.url-input {
width: 100%;
padding: 12px;
border: 2px solid $gray-light-color;
border-radius: 4px;
font-size: 16px;

&:focus {
outline: none;
border-color: $primary-color;
}
}

.help-text {
display: block;
margin-top: 6px;
color: $gray-light-color;
font-size: 14px;
line-height: 1.4;
}
}

.button-section {
display: flex;
gap: 10px;
margin-bottom: 20px;
flex-wrap: wrap;

.app-button {
flex: 1;
min-width: 120px;
}
}

.current-config {
padding: 15px;
background-color: #f5f5f5;
border-radius: 4px;
font-size: 14px;
line-height: 1.4;

.current-url {
display: block;
margin-top: 5px;
word-break: break-all;
color: $primary-color;
font-family: monospace;
}
}
}
}
</style>
4 changes: 2 additions & 2 deletions src/components/AppAlert.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
</template>

<script lang="ts">
import { createComponent } from '@vue/composition-api'
import { defineComponent } from 'vue'

export default createComponent({
export default defineComponent({
name: 'AppAlert',
props: {
alert: {
Expand Down
Loading