@@ -32,6 +32,8 @@ import {
3232} from "../reducers/project-state" ;
3333
3434import { supabase } from "./supabase-client" ;
35+ import { v4 as uuidv4 } from "uuid" ;
36+ import { setProjectId } from "../reducers/project-state" ;
3537
3638/**
3739 * Higher Order Component to provide behavior for saving projects.
@@ -168,26 +170,22 @@ const ProjectSaverHOC = function (WrappedComponent) {
168170 async updateProjectToStorage ( ) {
169171 if ( this . props . loadingState === "MANUAL_UPDATING" ) {
170172 const blob = await this . props . vm . saveProjectSb3 ( ) ;
171- console . log ( this . props ) ;
172173 const { data : fileData , error : errorData } = await supabase
173174 . from ( "files" )
174175 . select ( "*" )
175176 . eq ( "id" , localStorage . getItem ( "project-id" ) )
176177 . single ( ) ;
177178 if ( errorData ) {
178- window . alert ( "文件保存失败" , error ) ;
179+ this . props . onShowAlert ( "savingError" ) ;
179180 return this . props . onProjectError ( errorData ) ;
180181 }
181- console . log ( fileData ) ;
182182 // 替换文件
183183 const { data : updateData , error : updateError } =
184184 await supabase . storage
185185 . from ( "files" )
186- . upload ( fileData . file_path , blob , {
187- upsert : true ,
188- } ) ;
186+ . upload ( fileData . file_path , blob , { upsert : true } ) ;
189187 if ( updateError ) {
190- window . alert ( "文件保存失败" , updateError ) ;
188+ this . props . onShowAlert ( "savingError" ) ;
191189 return this . props . onProjectError ( updateError ) ;
192190 }
193191 // 替换缩略图
@@ -200,7 +198,7 @@ const ProjectSaverHOC = function (WrappedComponent) {
200198 const { data : updateData , error : updateError } =
201199 await supabase . storage
202200 . from ( "files" )
203- . upload ( filePath , blob ) ;
201+ . upload ( filePath , blob , { upsert : true } ) ;
204202 if ( updateError ) {
205203 this . props . onShowAlert ( "savingError" ) ;
206204 return this . props . onProjectError ( updateError ) ;
@@ -210,7 +208,7 @@ const ProjectSaverHOC = function (WrappedComponent) {
210208 . update ( { thumbnail_path : filePath } )
211209 . eq ( "id" , fileData . id ) ;
212210 if ( error ) {
213- window . alert ( "文件保存失败" , error ) ;
211+ this . props . onShowAlert ( "savingError" ) ;
214212 return this . props . onProjectError ( errorData ) ;
215213 }
216214 } ) ;
@@ -221,7 +219,7 @@ const ProjectSaverHOC = function (WrappedComponent) {
221219 . update ( { file_name : this . props . reduxProjectTitle } )
222220 . eq ( "id" , fileData . id ) ;
223221 if ( error ) {
224- window . alert ( "文件保存失败" , error ) ;
222+ this . props . onShowAlert ( "savingError" ) ;
225223 return this . props . onProjectError ( errorData ) ;
226224 }
227225 }
@@ -242,28 +240,59 @@ const ProjectSaverHOC = function (WrappedComponent) {
242240 this . props . onProjectError ( err ) ;
243241 } ) ;
244242 }
245- createCopyToStorage ( ) {
246- this . props . onShowCreatingCopyAlert ( ) ;
247- return this . props . onCreatedProject (
248- response . id . toString ( ) ,
249- this . props . loadingState
250- ) ;
251- // return this.storeProject(null, {
252- // originalId: this.props.reduxProjectId,
253- // isCopy: 1,
254- // title: this.props.reduxProjectTitle,
255- // })
256- // .then((response) => {
257- // this.props.onCreatedProject(
258- // response.id.toString(),
259- // this.props.loadingState
260- // );
261- // this.props.onShowCopySuccessAlert();
262- // })
263- // .catch((err) => {
264- // this.props.onShowAlert("creatingError");
265- // this.props.onProjectError(err);
266- // });
243+ async createCopyToStorage ( ) {
244+ const {
245+ data : {
246+ session : { user } ,
247+ } ,
248+ } = await supabase . auth . getSession ( ) ;
249+ const fileName = this . props . reduxProjectTitle ;
250+ const uuid = uuidv4 ( ) ;
251+ const filePath = `${ user . id } /${ uuid } .sb3` ;
252+ const thumbnailPath = `${ user . id } /${ uuid } .png` ;
253+ const blob = await this . props . vm . saveProjectSb3 ( ) ;
254+ // 上传sb3
255+ const { error : uploadError } = await supabase . storage
256+ . from ( "files" )
257+ . upload ( filePath , blob ) ;
258+ if ( uploadError ) {
259+ this . props . onShowAlert ( "另存为失败" ) ;
260+ return this . props . onProjectError ( errorData ) ;
261+ }
262+ // 上传缩略图
263+ this . getProjectThumbnail ( async ( dataURI ) => {
264+ const blob = dataURItoBlob ( dataURI ) ;
265+ const { data : updateData , error : updateError } =
266+ await supabase . storage
267+ . from ( "files" )
268+ . upload ( thumbnailPath , blob ) ;
269+ if ( updateError ) {
270+ this . props . onShowAlert ( "另存为失败" ) ;
271+ return this . props . onProjectError ( errorData ) ;
272+ }
273+ } ) ;
274+ // 上传record
275+ const { data : insertData , error : insertError } = await supabase
276+ . from ( "files" )
277+ . insert ( {
278+ user_id : user . id , // ⚠️ 必须是 auth 用户 id
279+ file_name : fileName ,
280+ file_path : filePath ,
281+ thumbnail_path : thumbnailPath ,
282+ } )
283+ . select ( ) ;
284+ if ( insertError ) {
285+ this . props . onShowAlert ( "另存为失败" ) ;
286+ return this . props . onProjectError ( errorData ) ;
287+ }
288+ // 打开新的文件
289+ const {
290+ data : { signedUrl : fileUrl } ,
291+ } = await supabase . storage
292+ . from ( "files" )
293+ . createSignedUrl ( insertData [ 0 ] . file_path , 60 * 60 ) ;
294+ localStorage . setItem ( "project-id" , insertData [ 0 ] . id ) ;
295+ storage . reduxStore . dispatch ( setProjectId ( fileUrl ) ) ;
267296 }
268297 createRemixToStorage ( ) {
269298 this . props . onShowCreatingRemixAlert ( ) ;
0 commit comments