on 1ec514b help sign in
252 lines 6.9 kB history raw
1import React, { Component } from 'react'
3import Button from '../components/Button'
4import UploadButton from '../components/UploadButton'
6import { compose } from '../lib/lib'
8import { PROFILE_STATES } from '../lib/constants'
11const NEXT_STEP_NUM = 3;
13const validateBase64 = ({ data, pass, error }) => {
14 if (pass !== true) return { data, pass, error }
16 try {
17 atob(data);
18 return { data: atob(data), pass: true, error: '' }
19 } catch(e) {
20 console.error(e)
21 return { data: data, pass: false, error: 'File is not valid base64.' }
22 }
25const validateJSON = ({ data, pass, error }) => {
26 if (pass !== true) return { data, pass, error }
28 try {
29 JSON.parse(data)
30 return { data: JSON.parse(data), pass: true, error: '' }
31 } catch(e) {
32 console.error(e)
33 return { data: data, pass: false, error: 'File does not decode into valid JSON.' }
34 }
37const validateFile = ({ data, pass, error }) => {
38 if (pass !== true) return { data, pass, error };
40 if (data.file.type !== 'text/plain') {
41 return { data: data, pass: false, error: 'File must be a .txt file' }
42 };
44 if (data.file.name.includes('urbit-ships') === false) {
45 return { data: data, pass: false, error: 'This does not appear to be the correct file.' }
46 };
48 return { data: data.event.target.result, pass, error };
53const validateObject = ({ data, pass, error }) => {
54 if (pass !== true) return { data, pass, error }
56 const checkStringField = (obj, field) =>
57 field in obj && typeof obj[field] === 'string';
59 const checkShipField = (obj, field) =>
60 field in obj || Array.isArray(obj[field]);
62 const meetsRequirements = obj =>
63 checkStringField(obj,'idCode')
64 && checkShipField(obj,'planets')
65 && checkShipField(obj,'stars')
66 && checkShipField(obj,'galaxies');
69 const didPass = meetsRequirements(data) ? true : false;
71 const err = didPass === false
72 ? 'File is missing data, or the data is of incorrect data type.'
73 : '';
75 return { data: data, pass: didPass, error: err }
78// const preview = ship => {
79// const name = ob.patp(ship)
80// const sig = sigil.pour({
81// patp: name,
82// colorway: ['black', 'white'],
83// renderer: ReactSVGComponents,
84// size: 64
85// })
86//
87// return (
88// <div className={'col-md-8'}>
89// <div className={'flex items-center bg-white black'} key={ ship }>
90// <div className={'col-md-5 pt-2 pl-5'}>
91// { sig }
92// </div>
93// <div className={'col-md-5'}>
94// <h4 className={'text-mono text-500 mb-0'}>
95// { name }
96// </h4>
97// </div>
98// </div>
99// </div>
100 // <div className={'flex h-16 w-60 bg-white black items-center'} key={ ship }>
101 // { sig }
102 // <div className={'pl-4 text-mono text-500'}>
103 // { name }
104 // </div>
105 // </div>
106// )
107// }
109// const shipList = profile => {
110// const ships = Object.keys(profile)
111// return(
112// <div>
113// <h2>Total Ships: { ships.length }</h2>
114//
115// <div className={''}>
116// { ships.map(preview) }
117// </div>
118// </div>
119// )
120// }
122class Upload extends Component {
123 constructor(props) {
124 super(props)
125 this.handleTXTUpload = this.handleTXTUpload.bind(this)
126 }
129 handleTXTUpload = (event) => {
130 const { setGlobalState } = this.props
131 const file = event.files.item(0)
132 const reader = new FileReader()
134 reader.onload = (event) => {
136 const validated = compose(
137 validateObject,
138 validateJSON,
139 validateBase64,
140 validateFile
141 )({ data: { event: event, file: file }, pass: true, error: '' })
143 if (validated.pass === true) {
144 const { galaxies, stars, planets } = validated.data
145 setGlobalState({
146 'profile.error': validated.error,
147 'profile.state': PROFILE_STATES.UPLOAD_SUCCESS,
148 'profile.value': validated.data,
149 'profile.shipCount': galaxies.length + stars.length + planets.length
150 })
151 } else {
152 setGlobalState({
153 'profile.error': validated.error,
154 'profile.state': PROFILE_STATES.UPLOAD_ERROR,
155 'profile.value': null,
156 })
157 }
158 }
160 reader.readAsText(file)
161 }
163 render() {
164 const { setGlobalState } = this.props;
166 const { props } = this;
168 const success =
169 props['profile.state'] === PROFILE_STATES.UPLOAD_SUCCESS ||
170 props['profile.state'] === PROFILE_STATES.INPUT_SUCCESS
172 let uploadButtonClass = props['profile.state'] === PROFILE_STATES.UPLOAD_ERROR
173 ? 'btn shape-orange'
174 : props['profile.state'] === PROFILE_STATES.UPLOAD_SUCCESS
175 ? 'btn btn-success'
176 : 'btn btn-primary'
178 let uploadButtonText = props['profile.state'] === PROFILE_STATES.UPLOAD_ERROR
179 ? 'Choose file again'
180 : props['profile.state'] === PROFILE_STATES.UPLOAD_SUCCESS
181 ? 'urbit-ships.txt'
182 : 'Choose file'
184 return(
185 <div className={'col-md-6'}>
186 <h2>{'Upload your '}<code>{'urbit-ships.txt'}</code></h2>
188 <p>{'This file contains your email and tells us what Urbit address space you own. Don’t have it? Return to Registration to download it.'}</p>
190 <UploadButton
191 className={ `${uploadButtonClass} table mt-4` }
192 onChange={ this.handleTXTUpload }
193 accept={'.txt'}
194 >
195 {uploadButtonText}
196 </UploadButton>
198 { props['profil.error'] !== ''
199 ? <p className={'orange'}>{props['profile.error']}</p>
200 : <div />
201 }
203 // { success
204 // ? <ShipList ships={props['profile.value'].galaxies} title={'Galaxies'} />
205 // : <div />
206 // }
207 //
208 // { success
209 // ? <ShipList ships={props['profile.value'].stars} title={'Stars'} />
210 // : <div />
211 // }
212 //
213 // { success
214 // ? <ShipList ships={props['profile.value'].planet} title={'Planets'} />
215 // : <div />
216 // }
219 <div className={'btn-tray'}>
220 { success
221 ? <div>
222 {
223 // <p>Missing ships? Email <a href={'mailto:registration@urbit.org'}>{'registration@urbit.org'}</a></p>
224 }
225 <Button
226 className={ success ? 'btn btn-primary mt-8' : 'btn shape-gray-10'}
227 disabled={ !success }
228 text={"I'm ready to begin →"}
229 onClick={ () => setGlobalState({ route: '/Understand', 'currentStep': NEXT_STEP_NUM })} />
230 </div>
231 : <div />
232 }
233 </ div>
234 </div>
235 )
236 }
239// const ShipList = (ships, title) => {
240// if (ships.length > 0) {
241// return (
242// <div>
243// <h2>{ title }</h2>
244// { ships.map(ship => preview(ship)) }
245// </div>
246// )
247// } else {
248// return <div />
249// }
250// }
252export default Upload