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